package com.bcxin.identify.config.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.identify.util.IpAddress;
import com.bcxin.identify.util.JedisUtils;
import com.bcxin.identify.util.Result;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * <b> IP过滤器，每次IP访问存redis计算次数，超过限制次数禁止访问 </b>
 * @author ZXF
 * @create 2019/12/31 0031 17:27
 * @version
 * @注意事项 </b>
 */
@Component
public class IPFilter implements Filter{

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    //最大访问次数
    private static final Integer MAX_COUNT = 10;

    //最长时间段(秒)
    private static final Long MAX_TIME_SECOND = 300L;

    private static String COUNT = "count";
    private static String TIME = "time";

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

    /**
     * <b> 过滤器业务处理，限制在5分钟内1个ip 1个链接最多访问10次 </b>
     * @author ZXF
     * @create 2025/09/09 0009 15:43
     * @version
     * @注意事项 </b>
     */
    @SuppressWarnings("unchecked")
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //得到当前请求的ip
        String ip = IpAddress.getIpAddress(request);
        //得到当前请求路径
        String url = request.getServletPath().replace("/","");
        String path = request.getRequestURL().toString().split("\\?")[0];
        if(StringUtils.isEmpty(url)){
            chain.doFilter(request, response);
            return;
        }
        if(noneUrl(request.getServletPath())){
            chain.doFilter(request, response);
            return;
        }
        //查询ip和次数
        int count = 0;
        Long time = System.currentTimeMillis();
        JSONObject json = null;
        try {
            //标识头+ip+路径
            String key = "IDENTIFY:CACHE:UIP-"+ip+"-"+url;
            if(JedisUtils.exists(key) && StringUtils.isNotEmpty(JedisUtils.get(key))) {
                json = JSON.parseObject(JedisUtils.get(key));
                count = Integer.parseInt(String.valueOf(json.get(COUNT)));
                Long initTime = Long.parseLong(String.valueOf(json.get(TIME)));
                //计算时差（秒）
                Long jetLag = ((time-initTime)/1000);
                //大于5分钟
                if(jetLag >= MAX_TIME_SECOND) {
                    logger.debug("      ====== IP过滤器 > 5m：key:"+key+",count:"+count+",jetLag:"+jetLag+" ======      ");
                    //重置次数，重置时间
                    setRedisContent(json, key, String.valueOf(1), String.valueOf(time));
                }else {
                    //判断是否超出次数：1.超出限制返回，2未超出次数叠加
                    if(count > MAX_COUNT) {
                        logger.debug("      ====== IP过滤器超出预期：key:"+key+",count:"+count+",jetLag:"+jetLag+" ======      ");
                        returnWriter("警告！！您的请求过于频繁，请稍后重试。", response);
                        return;
                    }else{
                        logger.debug("      ====== IP过滤器 < 5m：key:"+key+",count:"+count+",jetLag:"+jetLag+" ======      ");
                        setRedisContent(json, key, String.valueOf(count+1), "");
                    }
                }
            }else{
                logger.debug("      ====== IP过滤器初始：key:"+key+",count:"+count+",time:"+time+" ======      ");
                //初始创建缓存记录
                setRedisContent(json, key, String.valueOf(count+1), String.valueOf(time));
            }
        } catch (Exception e) {
            returnWriter("IP过滤器业务处理异常，ERROR："+e.getMessage(), response);
            return;
        }

        chain.doFilter(request, response);
    }

    /**
     * <b> 添加不限制请求次数的链接标识 </b>
     * @author ZXF
     * @create 2020/05/15 0015 9:58
     * @version
     * @注意事项 </b>
     */
    private static boolean noneUrl(String url){
        if(url.contains("/admin")){
            return true;
        }
        return false;
    }

    private static void setRedisContent(JSONObject json, String key, String count, String time){
        if(json == null){
            json = new JSONObject();
        }
        if(StringUtils.isNotEmpty(count)){
            json.put(COUNT,count);
        }
        if(StringUtils.isNotEmpty(time)){
            json.put(TIME,time);
        }
        JedisUtils.set(key, json.toString(), 1 * 60 * 60);
    }

    private static void returnWriter(String msg, HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        response.getWriter().print(JSON.toJSONString(Result.fail(msg)));
    }

    @Override
    public void destroy() {}
}
