package com.jwipc.util;

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.Base64;

/**
 * @author qizhicai
 * @version JDK 1.8
 * @date 2025/11/26
 * @description TODO
 */
public class HmacUtil {
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";

    /**
     *
     * @param userId 用户工号
     * @param appType 系统类型
     * @param key  密钥
     * @return
     */
    public static String hmacSha256(String userId, String  appType, String key) {
        long timestamp = System.currentTimeMillis();
        String data = userId + "|" + appType + "|" + timestamp;
        // 构造payload: userId|appType|timestamp
        try {
            SecretKeySpec signingKey = new SecretKeySpec(
                    key.getBytes(StandardCharsets.UTF_8),
                    HMAC_SHA256_ALGORITHM
            );
            Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return  Base64.getEncoder().encodeToString((data + "|" + bytesToHex(rawHmac)).getBytes());
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to generate HMAC-SHA256 signature", e);
        }
    }

    public static String hmacSha256(String data, String key) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(
                    key.getBytes(StandardCharsets.UTF_8),
                    HMAC_SHA256_ALGORITHM
            );
            Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(rawHmac);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to generate HMAC-SHA256 signature", e);
        }
    }

    /**
     * 字节数组转十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    /**
     * 验证HMAC-SHA256签名
     * @param data 原始数据
     * @param key 密钥
     * @param signature 待验证签名
     * @return 是否验证通过
     */
    public static boolean verifyHmacSha256(String data, String key, String signature) {
        String generatedSignature = hmacSha256(data, key);
        return generatedSignature.equals(signature);
    }

    public static final String SECRET_KEY = "v3j^8Pm*9x1Lw!z!Q2tR$kY5hJ7nG4eD6sF8aK9pO0iU-qW=rX+yZ(lB)N_cV@M";
    private static final long EXPIRE_TIME = 5 * 60 * 1000; // 5分钟


        public static void main(String[] args) {
            // 生成签名部分
            String userId = "ZWZN1755";
            String appType = "zwznsrm";
            long timestamp = System.currentTimeMillis();

            // 构造payload: userId|appType|timestamp
            String payload = userId + "|" + appType + "|" + timestamp;
            String signature = HmacUtil.hmacSha256(userId,appType, SECRET_KEY);
            System.out.println("signature:" + signature);

          //  String sign = Base64.getEncoder().encodeToString((payload + "|" + signature).getBytes());
            System.out.println("加密信息：" + signature);

            // 解密和验证部分
            String decoded = new String(Base64.getDecoder().decode(signature));
            System.out.println("解密信息：" + decoded);

            String[] parts = decoded.split("\\|");
            if (parts.length != 4) {
                System.out.println("验证失败：无效的签名格式");
                return;
            }

            // 提取各部分
            String receivedUserId = parts[0];
            String receivedAppType = parts[1];
            long receivedTimestamp;
            try {
                receivedTimestamp = Long.parseLong(parts[2]);
            } catch (NumberFormatException e) {
                System.out.println("验证失败：无效的时间戳格式");
                return;
            }
            String receivedSignature = parts[3];

            // 验证时间戳
            long currentTime = System.currentTimeMillis();
            if (Math.abs(currentTime - receivedTimestamp) > EXPIRE_TIME) {
                System.out.println("验证失败：签名已过期");
                return;
            }

            // 重新构造payload进行签名验证
            String payloadForVerification = receivedUserId + "|" + receivedAppType + "|" + receivedTimestamp;
            boolean isSignatureValid = verifyHmacSha256(payloadForVerification, SECRET_KEY, receivedSignature);

            if (isSignatureValid) {
                System.out.println("验证成功：签名有效且未过期");
            } else {
                System.out.println("验证失败：签名无效");
            }
        }

}
