package com.fs.live.utils;

import com.alibaba.fastjson.JSONObject;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author MixLiu
 * @date 2025/9/9 下午3:07)
 */
public class CryptoUtil {

    // 默认密钥
    private static final String DEFAULT_SECRET_KEY = "8a3f7d1e4c9b2a6f5e8d3c7a1b9f2ed5";

    // 加密算法
    private static final String ALGORITHM = "AES";

    // 签名算法
    private static final String SIGN_ALGORITHM = "HmacSHA256";

    public static void main(String[] args) {
        JSONObject mp = new JSONObject();
        mp.put("unionId", "012312312444");
        SignedData signedData = JSONObject.parseObject("{\n" +
                "\t\t\"data\": \"Q0NaCEMBVhdVDxtYBFEaREAWXRZ6BxVbBVIMVwdVXQAJVU4=\",\n" +
                "\t\t\"signature\": \"WO7vzLZwGyFLLMvaMEDsn4+kUM9RyASMDR/eckKrWzg=\"\n" +
                "\t}", SignedData.class);
//        SignedData signedData = encryptAndSignRequest(mp.toString());
//        System.out.println(signedData.toString());
        String decryptedText = decryptAndVerifyResponse(signedData);
        System.out.println(decryptedText);
    }
    /**
     * 客户端：加密请求参数并签名
     * @param plainText 明文参数
     * @return 加密并签名后的数据对象
     */
    public static SignedData encryptAndSignRequest(String plainText) {
        return encryptAndSign(plainText, DEFAULT_SECRET_KEY);
    }

    /**
     * 客户端：解密并验证响应参数
     * @param signedData 签名的数据对象
     * @return 解密后的明文
     * @throws SecurityException 验签失败时抛出异常
     */
    public static String decryptAndVerifyResponse(SignedData signedData) throws SecurityException {
        return decryptAndVerify(signedData, DEFAULT_SECRET_KEY);
    }

    /**
     * 服务端：解密并验证请求参数
     * @param signedData 签名的数据对象
     * @return 解密后的明文
     * @throws SecurityException 验签失败时抛出异常
     */
    public static String decryptAndVerifyRequest(SignedData signedData) throws SecurityException {
        return decryptAndVerify(signedData, DEFAULT_SECRET_KEY);
    }

    /**
     * 服务端：加密并签名响应参数
     * @param plainText 明文响应参数
     * @return 加密并签名后的数据对象
     */
    public static SignedData encryptAndSignResponse(String plainText) {
        return encryptAndSign(plainText, DEFAULT_SECRET_KEY);
    }

    /**
     * 通用加密并签名方法
     * @param plainText 明文
     * @param secretKey 密钥
     * @return 签名的数据对象
     */
    private static SignedData encryptAndSign(String plainText, String secretKey) {
        try {
            // 加密数据
            String encryptedData = encrypt(plainText, secretKey);

            // 生成签名
            String signature = generateSignature(encryptedData, secretKey);

            return new SignedData(encryptedData, signature);
        } catch (Exception e) {
            throw new RuntimeException("加密和签名失败", e);
        }
    }

    /**
     * 通用解密并验签方法
     * @param signedData 签名的数据对象
     * @param secretKey 密钥
     * @return 解密后的明文
     * @throws SecurityException 验签失败时抛出异常
     */
    private static String decryptAndVerify(SignedData signedData, String secretKey) throws SecurityException {
        try {
            // 验证签名
            String computedSignature = generateSignature(signedData.getData(), secretKey);
            if (!computedSignature.equals(signedData.getSignature())) {
                throw new SecurityException("数据签名验证失败");
            }

            // 解密数据
            return decrypt(signedData.getData(), secretKey);
        } catch (Exception e) {
            throw new RuntimeException("解密和验签失败", e);
        }
    }

    /**
     * 通用加密方法
     * @param plainText 明文
     * @param secretKey 密钥
     * @return 加密后的密文
     */
    private static String encrypt(String plainText, String secretKey) {
        try {
            // 简化示例：这里使用简单的异或加密，实际应用中应该使用AES等标准加密算法
            byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
            byte[] textBytes = plainText.getBytes(StandardCharsets.UTF_8);
            byte[] encryptedBytes = new byte[textBytes.length];

            for (int i = 0; i < textBytes.length; i++) {
                encryptedBytes[i] = (byte) (textBytes[i] ^ keyBytes[i % keyBytes.length]);
            }

            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    /**
     * 通用解密方法
     * @param encryptedText 密文
     * @param secretKey 密钥
     * @return 解密后的明文
     */
    private static String decrypt(String encryptedText, String secretKey) {
        try {
            // 简化示例：对应上面的异或解密
            byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            byte[] decryptedBytes = new byte[encryptedBytes.length];

            for (int i = 0; i < encryptedBytes.length; i++) {
                decryptedBytes[i] = (byte) (encryptedBytes[i] ^ keyBytes[i % keyBytes.length]);
            }

            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }

    /**
     * 生成数据签名
     * @param data 数据
     * @param secretKey 密钥
     * @return 签名
     */
    private static String generateSignature(String data, String secretKey) {
        try {
            Mac mac = Mac.getInstance(SIGN_ALGORITHM);
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), SIGN_ALGORITHM);
            mac.init(secretKeySpec);
            byte[] signatureBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(signatureBytes);
        } catch (Exception e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    /**
     * 签名数据类
     */
    public static class SignedData {
        private String data;        // 加密后的数据
        private String signature;   // 数据签名

        public SignedData() {}

        public SignedData(String data, String signature) {
            this.data = data;
            this.signature = signature;
        }

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }

        public String getSignature() {
            return signature;
        }

        public void setSignature(String signature) {
            this.signature = signature;
        }
    }
}
