package com.td.WaDa.filter;


import cn.hutool.core.convert.Convert;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.td.WaDa.common.pojo.ParameterRequestWrapper;
import com.td.WaDa.common.pojo.Result;
import com.td.WaDa.config.enums.ResultEnum;
import com.td.WaDa.util.*;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
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.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author:slambb
 * @date:2021/03/27
 */
@Slf4j
public class gameFilter implements Filter {
    @Value("${jwt.token}")
    private String tokenHeader;

    @Value("${server.servlet.context-path:}")
    private String contextPath;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    //添加redis 防止恶意请求
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedisSettingMap redisSettingMap;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //处理跨域请求
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept , Authorization");

        //log.info("********进入GameFilter过滤器********");
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        //登陆IP不在白名单
        String ipAddr = IpUtil.getIpAddr(req);

        String token = req.getHeader(tokenHeader);
        String path = req.getServletPath();

        //这里三个接口给DApp后台调用,需要指定ip访问
        if (path.indexOf("getSNBAndFreeze") > -1
                || path.indexOf("setSNBAndUnfreeze") > -1
                || path.indexOf("cntPlayback") > -1) {
            log.info("ipAddr:" + ipAddr);
            String limitedIp = redisSettingMap.getSysSettingLimitMap().getLimitedIp();
            if (StringUtils.hasText(limitedIp) && !Arrays.asList(limitedIp.split(",")).contains(ipAddr)) {
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                PrintWriter out = response.getWriter();

                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.LOGIN_IP_IS_ERROR.getMessage(), ResultEnum.LOGIN_IP_IS_ERROR.getCode())));
                out.flush();
                out.close();
                return;
            }
            filterChain.doFilter(servletRequest, response);
            return;
        }

        /**
         * 除了上面三个提供给DApp的接口，剩下的game接口都需要限制访问
         */
        //设置20秒内可以访问10次，同一个接口
        String redisKey = "limit-req:".concat(req.getRequestURL().toString()).concat(":").concat(ipAddr);
        if (!redisTemplate.hasKey(redisKey)) {
            redisTemplate.opsForValue().set(redisKey, String.valueOf(1), 20, TimeUnit.SECONDS);
        } else {
            int increment = Convert.toInt(redisTemplate.opsForValue().get(redisKey));
            if (increment > 10) {
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                PrintWriter out = response.getWriter();
                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.REDIS_IS_LOCK.getMessage(), ResultEnum.REDIS_IS_LOCK.getCode())));
                out.flush();
                out.close();
                return;
            } else {
                redisTemplate.opsForValue().set(redisKey, String.valueOf(++increment), 20, TimeUnit.SECONDS);
            }
        }

        //登录，获取验证码，不用登录的接口
        // 存在game字段，需要检验token
        if (!(path.indexOf("game") > -1)
                || path.indexOf("loginToken") > -1
                || path.indexOf("login") > -1
                || path.indexOf("RSAConfig") > -1
        ) {
            //登录情况直接放行
            filterChain.doFilter(servletRequest, response);
            return;
        }


        if (null == token || token.isEmpty() || !token.startsWith("Bearer ")) {
            //没有token信息
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter out = response.getWriter();
            out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.TOKEN_DOES_NOT_EXIST.getMessage(), ResultEnum.TOKEN_DOES_NOT_EXIST.getCode())));
            out.flush();
            out.close();
            return;
        } else {
            String authToken = token.substring(7);
            try {
                String userId = jwtTokenUtil.getUserIdFromToken(authToken);
                //log.info("userId:{}", userId);
                //todo 后面需要校验时间，加入可切换 secret 校验
                //log.info("validateToken:{}", jwtTokenUtil.validateToken(authToken, userId));
                // 加入secret校验
                if (!jwtTokenUtil.validateToken(authToken, userId)) {
                    log.info("secret 不可靠，validateToken:{}", jwtTokenUtil.validateToken(authToken, userId));
                }
                if (StringUtils.hasText(userId)) {
                    filterChain.doFilter(new TokenRequestWrapper((HttpServletRequest) servletRequest, userId), response);
                } else {
                    //不存在用户信息
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json; charset=utf-8");
                    PrintWriter out = response.getWriter();
                    out.print(JsonUtils.toJson(Result.of(authToken, false, ResultEnum.TOKEN_DOES_NOT_HAVE_USER_ID.getMessage(), ResultEnum.TOKEN_DOES_NOT_HAVE_USER_ID.getCode())));
                    out.flush();
                    out.close();
                }
            } catch (ExpiredJwtException e) {
                //token过期
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                PrintWriter out = response.getWriter();
                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.TOKEN_OUT_OF_DATE.getMessage(), ResultEnum.TOKEN_OUT_OF_DATE.getCode())));
                out.flush();
                out.close();
            } catch (SignatureException e) {
                //secret校验密钥不对
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                PrintWriter out = response.getWriter();
                out.print(JsonUtils.toJson(Result.of(authToken, false, ResultEnum.TOKEN_IS_ILLEGAL.getMessage(), ResultEnum.TOKEN_IS_ILLEGAL.getCode())));
                out.flush();
                out.close();
            }

        }

    }
}
