package com.cool.store.config;

import com.alibaba.fastjson.JSON;
import com.cool.store.constants.CommonConstants;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.response.ResponseResult;
import com.cool.store.utils.OpenSignatureUtil;
import com.cool.store.utils.UUIDUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
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 javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;

/**
 * 接口映射 红圈通系统使用新验签,  云流水，新管家等使用旧的验签模式
 * @Author suzhuhong
 * @Date 2025/4/5 18:11
 * @Version 1.0
 */


@Component
@Order(3)
@Slf4j
public class OpenApiValidateFilter implements Filter {

    @Value("${cool.api.appKey}")
    private String coolAppKey;
    @Value("${cool.api.secret}")
    private String coolAppSecret;
    private static final Set<String> WHITELIST_URIS = new HashSet<>(Arrays.asList(
            "/zxjp/open/v1/statusRefresh",
            "/zxjp/open/v1/getStoreUser",
            "/zxjp/open/v1/callback"
    ));
    private static final List<String> oldUrlMapping = new ArrayList<>(Arrays.asList(
            "/zxjp/open/v1/statusRefresh","/zxjp/open/v1/changePaymentStatus",
            "/zxjp/open/v1/getYlsToken", "/zxjp/open/v1/getStoreList",
            "/zxjp/open/v1/changeReceiptStatus", "/zxjp/open/v1/getStoreUser"));

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

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        if(!uri.startsWith("/zxjp/open/v1")){
            filterChain.doFilter(servletRequest, response);
            return;
        }
        MDC.put(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID());
        //statusRefresh 放开不需要验签
        if (isWhitelistUri(uri)) {
            filterChain.doFilter(servletRequest, response);
            return;
        }
        HttpServletResponse res = (HttpServletResponse) response;
        // 1. 验证时间戳
        try {
            String timestampStr = request.getHeader("timestamp");
            if (timestampStr == null) {
                log.info("timestampStr is null {}", "缺少timestamp参数");
                res.setStatus(HttpStatus.OK.value());
                res.setCharacterEncoding("UTF-8");
                res.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL, "缺少timestamp参数")));
                return;
            }
            long timestamp = Long.parseLong(timestampStr) / 1000;
            long currentTime = System.currentTimeMillis() / 1000;
            long timeDiff = Math.abs(currentTime - timestamp);
            try {
                if (timeDiff > 600) {
                    log.info("OpenApiValidateFilter==>{}","请求已过期，服务器时间:" + currentTime + " 请求时间:" + timestamp);
                    throw new ServiceException(ErrorCodeEnum.SIGN_FAIL,"请求已过期，请保证timestamp时间在10分钟之内");
                }
            } catch (NumberFormatException e) {
                log.info("OpenApiValidateFilter==>{}","非法timestamp格式");
                res.setStatus(HttpStatus.OK.value());
                res.setCharacterEncoding("UTF-8");
                res.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL,"非法timestamp格式")));
                return;
            }

            // 2. 验证签名
            String appKey = request.getHeader("appkey");
            if (appKey == null || !coolAppKey.equals(appKey)) {
                log.info("OpenApiValidateFilter==>{}","无效的appKey");
                res.setStatus(HttpStatus.OK.value());
                res.setCharacterEncoding("UTF-8");
                res.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL,"无效的appKey")));
                return;
            }

            String clientSign = request.getHeader("sign");
            if (clientSign == null) {
                res.setStatus(HttpStatus.OK.value());
                res.setCharacterEncoding("UTF-8");
                res.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL,"签名为空")));
                return;
            }
            // 1. 读取请求体
            StringBuilder requestBody = new StringBuilder();
            try (BufferedReader reader = request.getReader()) {
                String line;
                while ((line = reader.readLine()) != null) {
                    requestBody.append(line);
                }
            }

            String jsonBody = requestBody.toString();
            String serverSign;
            //接口映射 红圈通系统使用新验签,  oldUrlMapping接口使用旧的验签模式 后续新增接口都使用新验签
            if (oldUrlMapping.contains(uri)) {
                serverSign = getOldSign(jsonBody, appKey, timestampStr);
            } else {
                serverSign = getNewSign(jsonBody, appKey, timestampStr);
            }

            log.info("serverSign{}", serverSign);

            if (!serverSign.equalsIgnoreCase(clientSign)) {
                res.setStatus(HttpStatus.OK.value());
                res.setCharacterEncoding("UTF-8");
                res.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL, "签名校验失败")));
                return;
            }
            filterChain.doFilter(request, response);
        } finally {
            MDC.clear();
        }
    }

    private @NotNull String getNewSign(String jsonBody, String appKey, String timestampStr) throws JsonProcessingException {
        // 2. 使用 Jackson 解析 JSON 并转为 TreeMap（自动按键排序）
        ObjectMapper objectMapper = new ObjectMapper();
        SortedMap<String, Object> params = objectMapper.readValue(
                jsonBody,
                new TypeReference<TreeMap<String, Object>>() {
                }
        );
        params.put("appKey", appKey);
        params.put("timestamp", timestampStr);

        return OpenSignatureUtil.generateSign(params, coolAppSecret);
    }

    private @NotNull String getOldSign(String jsonBody, String appKey, String timestampStr) throws JsonProcessingException {
        // 2. 使用 Jackson 解析 JSON 并转为 TreeMap（自动按键排序）
        ObjectMapper objectMapper = new ObjectMapper();
        SortedMap<String, String> params = objectMapper.readValue(
                jsonBody,
                new TypeReference<TreeMap<String, String>>() {
                }
        );
        params.put("appKey", appKey);
        params.put("timestamp", timestampStr);

        return OpenSignatureUtil.generateOldSign(params, coolAppSecret);
    }

    private boolean isWhitelistUri(String uri) {
        return WHITELIST_URIS.stream().anyMatch(uri::startsWith);
    }
    @Override
    public void destroy() {
    }
}