package com.cool.store.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.context.PartnerUserHolder;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.response.ResponseResult;
import com.cool.store.service.WechatMiniAppService;
import com.cool.store.utils.*;
import com.cool.store.utils.poi.StringUtils;
import com.cool.store.vo.PartnerUserInfoVO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @author ydw
 * @Description 权限校验
 * @date 2020/1/15
 */
@Component
@Order(3)
@Slf4j
public class SignValidateFilter implements Filter {

    @Resource
    private WechatMiniAppService wechatMiniAppService;

    @Value("${signKey}")
    private String signKey;

    private static AntPathMatcher matcher = new AntPathMatcher();

    private static List<String> patternList =
            Lists.newArrayList(
                    "/web/check/ok",
                    "/check/ok",
                    "/zxjp/doc.html",
                    "/zxjp/favicon.ico",
                    "/zxjp/v2/api-docs","/**/test/**",
                    "/zxjp/mini/program/oss/getUploadFileConfig",
                    "/zxjp/mini/program/v1/partnerManage/partner/getIdentityCardInfo",
                    "/**/swagger*/**",
                    "/**/webjars/**",
                    "/zxjp/mini/program/v1/partnerManage/openArea/areaApplyQuery",
                    "/zxjp/**/api/audit/result",
                    "/zxjp/**/api/license",
                    "/zxjp/mini/line/getRegionPayPic"

            );


    /**
     * @param uri
     * @return boolean
     * @throws
     * @Title excludePath
     * @Description 是否是放行的请求
     */
    private boolean excludePath(String uri) {
        for (String pattern : patternList) {
            if (matcher.match(pattern, uri)) {
                return true;
            }
        }
        return false;
    }

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

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        if(uri.startsWith("/zxjp/pc")){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        MDC.put(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID());
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;
        String method = request.getMethod();
        String userStr = "";
        boolean isInWhiteList = excludePath(uri);
        log.info("url:{}, method:{}", uri, method);
        if ( !isInWhiteList && !method.equals("OPTIONS")) {
            String params = "";
            if("GET".equalsIgnoreCase(method)){
                params  =  request.getQueryString();
            }else if("POST".equalsIgnoreCase(method)){
                params = wrapper.getBody();
            }
            log.info("params:{}", params);
            String sign = request.getHeader("SIGN");
            String nonce = request.getHeader("NONCE");
            String timestamp = request.getHeader("TIMESTAMP");
            String aesPhone = request.getHeader("PHONE");
            String openid = request.getHeader("OPENID");
            if(StringUtils.isAnyBlank(sign, nonce, timestamp, aesPhone, openid)){
                throw new ServiceException(ErrorCodeEnum.SIGN_FAIL);
            }
            log.info("aesPhone:{}, signKey:{}", aesPhone, signKey);
            String phone = AESDecryptor.decrypt(aesPhone, signKey);
            String plaintextOpenid = AESDecryptor.decrypt(openid, signKey);
            String md5Value = phone + Md5Utils.md5(Md5Utils.md5(plaintextOpenid));
            log.info("sign:{}, nonce:{}, timestamp:{},aesPhone:{}, openid:{}, 解密后的手机号:{}, md5Value:{}, 明文plaintextOpenid:{}",
                    sign, nonce, timestamp, aesPhone, openid, phone, md5Value, plaintextOpenid);
            String signStr = timestamp + nonce + params + signKey + md5Value;
            String newSign = Sha1Utils.getSha1(signStr.getBytes());
            log.info("signStr: {}, newSign: {}", signStr, newSign);
            // 前后端验签不等
            if (!newSign.equals(sign)) {
                response.setStatus(HttpStatus.OK.value());
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write(JSON.toJSONString(ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL)));
                return;
            }
            PartnerUserInfoVO partnerUserInfoVO = wechatMiniAppService.getUserInfo(phone, plaintextOpenid);
            if(partnerUserInfoVO != null){
                userStr = JSONObject.toJSONString(partnerUserInfoVO);
                log.info("userStr:{}", userStr);
            }
        }
        try {
            PartnerUserHolder.setUser(userStr);
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            PartnerUserHolder.removeUser();
            MDC.clear();
        }
    }

    @Override
    public void destroy() {
        //do nothing
    }
}
