package fastweb.config;

import com.google.gson.Gson;
import fastweb.domain.system.WrapperResult;
import fastweb.domain.usertype.User;
import fastweb.respository.userType.UserRepository;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;

public class JwtAuthenticationFilter extends GenericFilterBean {
    private final UserRepository sysUserDao;
    private final StringRedisTemplate stringRedisTemplate;

    private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    public JwtAuthenticationFilter(UserRepository sysUserDao, StringRedisTemplate stringRedisTemplate) {
        this.sysUserDao = sysUserDao;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        // 从Http头中取Header
        String token = ((HttpServletRequest) request).getHeader("token");
        if (token == null) {
            token = request.getParameter("token");
        }
        if (token != null) {
            // 校验JWT
            R r = JwtUtil.valid(token);
            if (stringRedisTemplate.hasKey(token) && r.isSuccess()) {
                // 校验成功需要设置权限
                String username = MapUtils.getString(r.getPayloadMap(), "username", StringUtils.EMPTY);
                Set<String> authoritySet = stringRedisTemplate
                        .boundSetOps(token)
                        .members();
                User sysUser = sysUserDao.findDistinctByAccount(username);
                UsernamePasswordAuthenticationToken authentication;
                if (authoritySet.isEmpty()) {
                    authentication = new UsernamePasswordAuthenticationToken(sysUser.getAccount(), sysUser.getPassword(), AuthorityUtils.createAuthorityList());
                } else {
                    authentication = new UsernamePasswordAuthenticationToken(sysUser.getAccount(), sysUser.getPassword(), AuthorityUtils.createAuthorityList(authoritySet.toArray(new String[]{})));
            }
                authentication.setDetails(sysUser);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                filterChain.doFilter(request, response);
            } else {
                writeResponse((HttpServletResponse) response);
            }
        } else {
            // 校验失败返回Token失效
            writeResponse((HttpServletResponse) response);
        }
    }

    private void writeResponse(HttpServletResponse response) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        Gson gson = new Gson();
        WrapperResult wrappedResult =  WrapperResult.failedWrappedResult("Token失效", null, "401");
        wrappedResult.setResultValue(null);
        response.getWriter().print(gson.toJson(wrappedResult));
    }

}
