package com.dxhy.auth.filter;

import com.dxhy.auth.config.UserCenterConfig;
import com.dxhy.common.constant.ConfigureConstant;
import com.dxhy.common.matcher.AntPathMatcher;
import com.dxhy.common.util.JsonUtils;
import com.dxhy.common.util.MD5;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Allen
 * @version 1.0.0
 * @ClassName Myfilter.java
 * @Description 请求鉴权过滤器
 * @createTime 2024年08月09日 15:30:00
 */
@WebFilter(urlPatterns = "/**")
@Component
@Slf4j
public class RequestAuthfilter implements Filter {
    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    @Autowired
    private UserCenterConfig userCenterConfig;

//    private CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {


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



        String servletPath = req.getServletPath();
//        log.info("请求鉴权过滤器执行,拦截地址：{}", servletPath);
        String link;
        //判断当前请求的URL是否在{Filter不拦截URL集合}中
        if (userCenterConfig.configExcludedPaths() != null && userCenterConfig.configExcludedPaths().trim().length() > 0) {
            String[] excludedPathArray = userCenterConfig.configExcludedPaths().split(",");
            for (String excludedPath : excludedPathArray) {
                link = excludedPath.trim();
                if (ANT_PATH_MATCHER.match(link, servletPath)) {
                    filterChain.doFilter(req,servletResponse);
                    return;
                }
            }
        }

        String contentType = StringUtils.isNotEmpty(req.getContentType())?req.getContentType():"";
//        log.info("content-type：{}", requestWrapper.getContentType());

//        if (contentType.contains("multipart/form-data")) {
//            MultipartHttpServletRequest multipartHttpServletRequest = multipartResolver.resolveMultipart(requestWrapper);
//            Enumeration<String> parameterNames = multipartHttpServletRequest.getParameterNames();
//            MultipartFile file = multipartHttpServletRequest.getFile("");
//
//            while (parameterNames.hasMoreElements()) {
//                String s = parameterNames.nextElement();
//                log.info(s+":{}", multipartHttpServletRequest.getParameter(s));
//            }
//
//        }


        StringBuilder sb = new StringBuilder();
        String method = req.getMethod();
        String uri = req.getRequestURI();

        String paramStr = "";

        //请求用户中心token,如果为自建,赋值sso_session_id
        String requestToken = req.getHeader(ConfigureConstant.DXHY_JX_SESSION_ID);
        String signature = req.getHeader(ConfigureConstant.DXHY_JX_SIGNATURE);

        StringBuilder yzSignStr = null;
        if (contentType.contains("multipart/form-data")) {
            yzSignStr = sb.append(method).append(uri).append(requestToken);

        } else {
            SafeHttpServletRequestWrapper requestWrapper = new SafeHttpServletRequestWrapper((HttpServletRequest) servletRequest);
            servletRequest = requestWrapper;
            String bodyString = requestWrapper.getBodyString();
            Enumeration<String> parameterNames = requestWrapper.getParameterNames();
            List<String> paramNames = new ArrayList<>();
            while (parameterNames.hasMoreElements()) {
                paramNames.add(parameterNames.nextElement());
            }
            if (!CollectionUtils.isEmpty(paramNames)) {
                List<String> collect = paramNames.stream().sorted().collect(Collectors.toList());
                int size = collect.size();
                for (int i = 0; i < size; i++) {
                    String paramName = collect.get(i);
                    if (StringUtils.isBlank(paramStr)) {
                        paramStr += "?";
                    }
                    paramStr += paramName+"="+requestWrapper.getParameter(paramName);
                    if (i <size - 1) {
                        paramStr +="&";
                    }
                }
            }

            yzSignStr = sb.append(method).append(uri).append(paramStr).append(bodyString).append(requestToken);
        }

//        log.info("yzSignStr={}",yzSignStr);
//        log.info("signature={}",signature);
        String newSignature = null;
        if (StringUtils.isNotBlank(yzSignStr)) {
            if (StringUtils.isNotBlank(signature)) {
                try {
                    newSignature = MD5.getEncode(yzSignStr.toString());
//                    log.info("newSignature={}", newSignature);
                    if (signature.equals(newSignature)) {
//                        log.info("请求鉴权通过。。。");
                        filterChain.doFilter(servletRequest, servletResponse);
                        return;
                    } else {
                        returnMessage(res, signature, newSignature);
                        return;
                    }
                } catch (Exception e) {
                    log.error("请求鉴权异常:{}", e);
                    throw new RuntimeException(e);
                }
            } else {
                log.info("请求签名为空。。method:{}。uri:{}",method,uri);
                returnMessage(res,signature, newSignature);
                return;
            }
        } else {
            log.info("请求原字签名串为空。。");
            returnMessage(res,signature, newSignature);
            return;
        }
    }

    private void returnMessage(HttpServletResponse res,String signature,String newSignature) throws IOException {
        log.error("请求鉴权未通过,前端传递的签名:{},后台计算的签名:{}", signature, newSignature);
        Map<String, String> paramMap = new HashMap<>(3);
        paramMap.put(ConfigureConstant.CODE, "5001");
        paramMap.put(ConfigureConstant.MSG, "Request Authentication Error");
        PrintWriter writer = res.getWriter();
        writer.write(JsonUtils.getInstance().toJsonString(paramMap));
        writer.close();
    }
}
