package com.gz.filter;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.gz.core.response.ResponseEnum;
import com.gz.core.response.ResponseResult;
import com.gz.jwt.JwtConfig;
import com.gz.jwt.JwtPayload;
import com.gz.utils.JwtUtils;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;

/**
 * @author LiuchangLan
 * @date 2021/1/28 22:06
 */
@Slf4j
@Setter
public class AuthFilter implements Filter {

    private StringRedisTemplate stringRedisTemplate;

    private String skipUrls;

    private String forceUrls;

    private AntPathMatcher matcher = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        // 设置请求字符集
        servletRequest.setCharacterEncoding("UTF-8");
        // 设置返回格式
        servletResponse.setContentType("application/json;charset=UTF-8");
        String uri = req.getRequestURI();
        String url = uri.replace(req.getContextPath(), "");

        boolean force = Arrays.stream(forceUrls.split(",")).anyMatch(e -> matcher.match(e, url));
        // 验证路径是否跳过
        boolean skip = Arrays.stream(skipUrls.split(",")).anyMatch(e -> matcher.match(e, url));

        if (!force || skip) {
            // 不进行token验证
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            // token验证
            String token = req.getHeader(JwtConfig.HEADER_ACCCESS_TOKEN);
            // token黑名单
            String BlackListKey = String.format(JwtConfig.BLACKLIST_KEY_FORMAT, token);
            // token为空
            if (StringUtils.isEmpty(token) || "undefined".equals(token)) {
                // 返回
                PrintWriter writer = servletResponse.getWriter();
                log.warn("token为空,禁止访问");
                ResponseResult result = new ResponseResult(ResponseEnum.ILLEGAL_TOKEN);
                writer.println(JSON.toJSONString(result));
            } else {
                // 在黑名单中
                if (stringRedisTemplate.opsForValue().get(BlackListKey) != null) {
                    // 返回
                    PrintWriter writer = servletResponse.getWriter();
                    log.warn("该token在黑名单中");
                    ResponseResult result = new ResponseResult(ResponseEnum.ILLEGAL_TOKEN);
                    writer.println(JSON.toJSONString(result));
                    return;
                }
                // 验证token
                boolean verifier = false;
                try {
                    verifier = JwtUtils.verifier(token);
                } catch (TokenExpiredException e) {
                    PrintWriter writer = servletResponse.getWriter();
                    log.warn("token验证失败,禁止访问");
                    ResponseResult result = new ResponseResult(ResponseEnum.TOKEN_EXPIRED);
                    writer.println(JSON.toJSONString(result));
                } catch (JWTDecodeException e) {
                    PrintWriter writer = servletResponse.getWriter();
                    log.warn("token验证失败,禁止访问");
                    ResponseResult result = new ResponseResult(ResponseEnum.ILLEGAL_TOKEN);
                    writer.println(JSON.toJSONString(result));
                }
                // 验证成功
                if (verifier) {
                    // 根据token获取载体
                    JwtPayload jwtPayload = JwtUtils.decrypt(token);
                    log.info("部门:{},用户:{},正在操作:{},用户id:{},部门id:{}", jwtPayload.getDeptName(), jwtPayload.getAdminName(), url, jwtPayload.getId(), jwtPayload.getDeptId());
                    // 放到请求中
                    req.setAttribute(JwtConfig.HEADER_AUTHORIZATION_USER, jwtPayload);
//                    log.info("token验证成功");
                    filterChain.doFilter(servletRequest, servletResponse);
                }
            }
//            log.info("请求的url:{}，请求的Token{}", url, token);
        }
    }
}
