package com.cool.store.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author su'zh
 */
@Slf4j
public class OpenSignatureUtil {
    private static final String HMAC_SHA256 = "HmacSHA256";

    public static String generateSign(Map<String, Object> params, String appSecret) {
        // 1. 分离固定参数和业务参数
        String appKey = params.get("appKey").toString();
        String timestamp = params.get("timestamp").toString();

        // 2. 创建不包含固定参数的临时Map用于排序
        Map<String, Object> sortedParams = new TreeMap<>(
                params.entrySet().stream()
                        .filter(e -> !"appKey".equals(e.getKey()))
                        .filter(e -> !"timestamp".equals(e.getKey()))
                        .filter(e -> !"sign".equals(e.getKey()))
                        .filter(e -> Objects.nonNull(e.getValue()))
                        .collect(Collectors.toMap(
                                Map.Entry::getKey,
                                Map.Entry::getValue
                            ))
                        );

        // 3. 构建参数字符串：业务参数（排序后） + 固定参数
        StringBuilder sb = new StringBuilder();

        // 3.1 添加排序后的业务参数
        sortedParams.forEach((key, value) -> {
            sb.append(key).append("=").append(JSONObject.toJSONString( value)).append("&");
        });

        // 3.2 添加固定参数（不参与排序）
        sb.append("appkey=").append(appKey)
                .append("&timestamp=").append(timestamp);
        log.info("待generateSign签名字符串：{}", sb);
        // 4. 生成签名
        return hmacSha256(sb.toString(), appSecret);

    }

    public static String generateOldSign(Map<String, String> params, String appSecret) {
        // 1. 分离固定参数和业务参数
        String appKey = params.get("appKey");
        String timestamp = params.get("timestamp");

        // 2. 创建不包含固定参数的临时Map用于排序
        Map<String, String> sortedParams = new TreeMap<>(
                params.entrySet().stream()
                        .filter(e -> !"appKey".equals(e.getKey()))
                        .filter(e -> !"timestamp".equals(e.getKey()))
                        .filter(e -> !"sign".equals(e.getKey()))
                        .filter(e -> e.getValue() != null && !e.getValue().isEmpty())
                        .collect(Collectors.toMap(
                                Map.Entry::getKey,
                                Map.Entry::getValue
                        ))
        );

        // 3. 构建参数字符串：业务参数（排序后） + 固定参数
        StringBuilder sb = new StringBuilder();

        // 3.1 添加排序后的业务参数
        sortedParams.forEach((key, value) -> {
            sb.append(key).append("=").append(value).append("&");
        });

        // 3.2 添加固定参数（不参与排序）
        sb.append("appkey=").append(appKey)
                .append("&timestamp=").append(timestamp);
        log.info("待generateOldSign签名字符串：{}", sb);
        // 4. 生成签名
        return hmacSha256(sb.toString(), appSecret);
    }


    private static String hmacSha256(String data, String key) {
        try {
            Mac sha256_HMAC = Mac.getInstance(HMAC_SHA256);
            SecretKeySpec secret_key = new SecretKeySpec(
                    key.getBytes(StandardCharsets.UTF_8),
                    HMAC_SHA256
            );
            sha256_HMAC.init(secret_key);
            byte[] hash = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hash);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
}