package com.haha.sdk.util;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

/**
 * 签名工具类
 * 
 * 重要说明：
 * 1. 主动调用哈哈平台的API接口（如开门、查询等）不需要签名
 * 2. 签名机制仅用于验证哈哈平台发送的回调通知（如开关门通知、识别结果通知等）
 * 3. 回调通知使用ticket进行验签，而非使用AppSecret
 * 
 * @author haha-sdk
 * @version 1.0.0
 */
public class SignUtils {
    
    /**
     * 生成签名
     * 签名算法：
     * 1. 将所有请求参数按照参数名ASCII码从小到大排序（字典序）
     * 2. 将排序后的参数拼接成字符串：key1=value1&key2=value2&...
     * 3. 在字符串末尾拼接 AppSecret
     * 4. 对拼接后的字符串进行MD5加密，得到签名值
     * 
     * @param params 请求参数
     * @param appSecret 应用密钥
     * @return 签名字符串
     */
    public static String generateSign(Map<String, String> params, String appSecret) {
        // 使用TreeMap自动按key排序
        TreeMap<String, String> sortedParams = new TreeMap<>(params);
        
        // 拼接参数
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            // 跳过sign参数本身
            if ("sign".equals(entry.getKey())) {
                continue;
            }
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(entry.getKey()).append("=").append(entry.getValue());
        }
        
        // 拼接AppSecret
        sb.append("&appsecret=").append(appSecret);
        
        // MD5加密
        return md5(sb.toString());
    }
    
    /**
     * MD5加密
     * 
     * @param str 待加密字符串
     * @return MD5加密后的字符串（32位小写）
     */
    public static String md5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5加密失败", e);
        }
    }
}
