package com.ruoyi.aicall.sign;

import com.ruoyi.aicall.sign.KeyPairGenerator;
import com.ruoyi.common.utils.CacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
public class SignVerifierUtils {

    private static final Map<String, Long> map = new ConcurrentHashMap<>();

    private static boolean isDuplicate(String nonce) {
        long now = System.currentTimeMillis();
        // 先清理 5 分钟之前的
        map.entrySet().removeIf(e -> now - e.getValue() > TimeUnit.MINUTES.toMillis(5));
        return map.putIfAbsent(nonce, now) != null;
    }

    public static String verify(HttpServletRequest req) {
        return verify(req, null);
    }
    public static String verify(HttpServletRequest req, String body) {
        String appKey   = req.getHeader("X-AppKey");
        String tsStr    = req.getHeader("X-Timestamp");
        String nonce    = req.getHeader("X-Nonce");
        String sign     = req.getHeader("X-Sign");
        if (appKey == null || tsStr == null || nonce == null || sign == null) {
            return "1001"; // 参数缺失
        }

        // 1. 时间窗口 ±5 分钟
        long ts = Long.parseLong(tsStr);
        if (Math.abs(System.currentTimeMillis() - ts) > 5 * 60 * 1000) {
            return "1002"; // 请求已过时或者时间戳不正确
        }

        // 2. 重复 nonce 判断；如果已缓存则拒绝
        if (isDuplicate(nonce)) {
            return "1003";          // 重复请求
        }

        // 3. 计算签名
        String secret = KeyPairGenerator.getSecretByAppKey(appKey);
        if (secret == null) return "1004"; // secret错误

        String base = null; // 按字典序拼接参数
        try {
            base = buildBaseString(req, body);
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(base);
        String expect = hmacSha256(secret, base);
        if(expect.equalsIgnoreCase(sign)){
            return "0000"; // 验签通过
        } else {
            return "1005"; // 签名错误
        }

    }

    /** 把 query + body 拼成待签字符串 */
    private static String buildBaseString(HttpServletRequest req, String body) throws IOException {
        // 3.1 解析 URL 查询
        Map<String,String[]> all = new TreeMap<>(req.getParameterMap());

        // 3.2 解析 body
        if ("application/x-www-form-urlencoded".equalsIgnoreCase(req.getContentType())) {
            // 表单：继续合并
            req.getParameterMap().forEach((k,v)-> all.merge(k,v,(a,b)->a));
        } else if ("application/json".equalsIgnoreCase(req.getContentType())) {
//            // JSON：把原始 body 读到 key=_body 里
//            String body = new BufferedReader(new InputStreamReader(req.getInputStream(), StandardCharsets.UTF_8))
//                    .lines().collect(Collectors.joining("\n"));
            all.put("_body", new String[]{body});
        }

        return all.entrySet().stream()
                .map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
                .collect(Collectors.joining("&"));
    }

    private static String hmacSha256(String secret, String msg) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            byte[] bytes = mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
            return DatatypeConverter.printHexBinary(bytes).toLowerCase();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        String sign1 = "19ede9e73b7fb607f4821d98f38fb6c390b5db0ecfef443a7de1deffc1e92f56";
        String sign2 = "e28d5f5ade52712629698d66e8f0c73a2abe6724413f73dbdfb00a13b46f18d1";
        String sign3 = "825762612fb99accb3d1b601f537665de79df6f4a2b77a8fef411bfcaa0c12c6";

    }
}
