package com.ygtx.common.utils;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SecureUtil;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * 加密工具类（RSA+AES）
 * 严格适配你提供的 Hutool 5.8.0 M3 版本的 RSA 类反编译代码
 */
public class CryptoUtils {
    // -------------------------- RSA 配置 --------------------------
    // 全局单例的 RSA 工具对象
    private static final RSA RSA_UTIL;

    // 静态代码块初始化 RSA 密钥对（核心：基于反编译的 RSA 类 API）
    static {
        try {
            // 1. 用 SecureUtil 生成 2048 位 RSA 密钥对（Hutool 通用工具类，兼容该版本）
            KeyPair keyPair = SecureUtil.generateKeyPair("RSA", 2048);
            // 2. 提取私钥和公钥
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            // 3. 用「私钥+公钥」初始化 RSA 对象（反编译的 RSA 类支持此构造方法）
            RSA_UTIL = new RSA(privateKey, publicKey);
        } catch (Exception e) {
            throw new RuntimeException("RSA 密钥对初始化失败", e);
        }
    }

    /**
     * 获取 RSA 公钥（Base64 编码，供前端使用）
     */
    public static String getRsaPublicKey() {
        try {
            PublicKey publicKey = RSA_UTIL.getPublicKey();
            // 将公钥字节数组编码为 Base64 字符串（便于网络传输）
            return Base64.encode(publicKey.getEncoded());
        } catch (Exception e) {
            throw new RuntimeException("获取 RSA 公钥失败", e);
        }
    }

    /**
     * RSA 私钥解密（解密前端传来的 AES 密钥）
     * @param encryptStr Base64 编码的加密字符串
     * @return 解密后的明文
     * 适配点：使用 KeyType.PRIVATE 枚举（反编译的 RSA 类的 decrypt 方法仅支持此参数）
     */
    public static String rsaDecrypt(String encryptStr) {
        try {
            // 1. 解码 Base64 加密字符串
            byte[] encryptBytes = Base64.decode(encryptStr);
            // 2. 私钥解密：严格使用 KeyType.PRIVATE 枚举（反编译的 RSA 类的方法签名要求）
            byte[] decryptBytes = RSA_UTIL.decrypt(encryptBytes, KeyType.PrivateKey);
            // 3. 转换为 UTF-8 明文
            return new String(decryptBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("RSA 解密失败", e);
        }
    }

    // -------------------------- AES 配置 --------------------------
    /**
     * AES 加密（CBC 模式，PKCS7 填充，带 IV 向量）
     * @param content 明文内容
     * @param aesKey AES 密钥（Base64 编码，16 位/32 位）
     * @return Base64 编码的密文
     */
    public static String aesEncrypt(String content, String aesKey) {
        try {
            // 解码 Base64 格式的 AES 密钥
            byte[] keyBytes = Base64.decode(aesKey);
            // 初始化 AES（CBC 模式，PKCS7 填充，密钥作为 IV 向量）
            AES aes = new AES("CBC", "PKCS7Padding", keyBytes, keyBytes);
            // 加密并编码为 Base64 字符串
            return Base64.encode(aes.encrypt(content));
        } catch (Exception e) {
            throw new RuntimeException("AES 加密失败", e);
        }
    }

    /**
     * AES 解密（解密前端传来的业务数据）
     * @param encryptStr Base64 编码的密文
     * @param aesKey AES 密钥（Base64 编码）
     * @return 解密后的明文
     */
    public static String aesDecrypt(String encryptStr, String aesKey) {
        try {
            // 解码 Base64 格式的 AES 密钥和密文
            byte[] keyBytes = Base64.decode(aesKey);
            byte[] encryptBytes = Base64.decode(encryptStr);
            // 初始化 AES（与加密端一致的模式和填充方式）
            AES aes = new AES("CBC", "PKCS7Padding", keyBytes, keyBytes);
            // 解密并转换为 UTF-8 明文
            byte[] decryptBytes = aes.decrypt(encryptBytes);
            return new String(decryptBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES 解密失败", e);
        }
    }

    public static void main(String[] args) {
        // 1. 获取公钥
        String publicKey = CryptoUtils.getRsaPublicKey();
        System.out.println("RSA 公钥：" + publicKey);

        // 2. 模拟前端用公钥加密 AES 密钥
        RSA rsa = new RSA(null, publicKey); // 仅传入公钥，用于加密
        String originalAesKey = "testAesKey123456";
        // 用公钥加密（使用 KeyType.PUBLIC 枚举，匹配 RSA 类方法签名）
        String encryptAesKey = rsa.encryptBase64(originalAesKey, KeyType.PublicKey);
        System.out.println("加密后的 AES 密钥：" + encryptAesKey);

        // 3. 用工具类解密
        String decryptAesKey = CryptoUtils.rsaDecrypt(encryptAesKey);
        System.out.println("解密后的 AES 密钥：" + decryptAesKey);

        // 验证解密结果
        assert originalAesKey.equals(decryptAesKey);
    }
}
