package common.utils.hyg;

import common.jfinal.AppConfig;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64; // 导入 Java 8+ 的标准 Base64 类

public class AESUtils {
    // 定义加密模式和填充方式
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
    // 定义加密算法
    private static final String ALGORITHM = "AES";

    /**
     * 根据加密后的十六进制字符串和密钥进行解密
     *
     * @param contentHex 加密后的十六进制字符串
     * @return 解密后的原始字符串
     * @throws Exception 如果解密过程中发生错误
     */
    public static String decryptByHex(String contentHex) throws Exception {
        String key = System.getenv("HYG_AES_KEY");
        // 调用内部解密方法
        return decryptByHex(contentHex, key);
    }

    /**
     * 根据加密后的十六进制字符串和密钥进行解密
     *
     * @param contentHex 加密后的十六进制字符串
     * @param key        Base64编码的密钥字符串
     * @return 解密后的原始字符串
     * @throws Exception 如果解密过程中发生错误
     */
    public static String decryptByHex(String contentHex, String key) throws Exception {
        // 将十六进制字符串转换为字节数组
        byte[] encryptBytes = hex2Byte(contentHex);
        // 调用内部解密方法
        return decrypt(encryptBytes, key);
    }

    /**
     * 内部解密过程
     *
     * @param encryptBytes 加密后的字节数组
     * @param key          Base64编码的密钥字符串
     * @return 解密后的原始字符串
     * @throws Exception 如果解密过程中发生错误
     */
    private static String decrypt(byte[] encryptBytes, String key) throws Exception {
        // 使用 java.util.Base64.getDecoder() 进行 Base64 解码
        Key k = toKey(Base64.getDecoder().decode(key));
        // 获取Cipher实例，指定加密模式和填充方式
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        // 初始化Cipher为解密模式 (Cipher.DECRYPT_MODE)
        cipher.init(Cipher.DECRYPT_MODE, k); // 参数2代表解密模式

        // 执行解密操作
        byte[] decryptedBytes = cipher.doFinal(encryptBytes);
        // 将解密后的字节数组转换为字符串，使用UTF-8编码
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 对内容进行加密，结果返回十六进制字符串
     *
     * @param content 原始字符串
     * @param key     Base64编码的密钥字符串
     * @return 加密后的十六进制字符串
     * @throws Exception 如果加密过程中发生错误
     */
    public static String encrypt2Hex(String content, String key) throws Exception {
        // 调用内部加密方法获取字节数组
        byte[] encryptBytes = encrypt(content, key);
        // 将字节数组转换为十六进制字符串
        return byte2Hex(encryptBytes);
    }

    /**
     * 内部加密过程
     *
     * @param content 原始字符串
     * @param key     Base64编码的密钥字符串
     * @return 加密后的字节数组
     * @throws Exception 如果加密过程中发生错误
     */
    private static byte[] encrypt(String content, String key) throws Exception {
        // 使用 java.util.Base64.getDecoder() 进行 Base64 解码
        Key k = toKey(Base64.getDecoder().decode(key));
        // 获取Cipher实例，指定加密模式和填充方式
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        // 初始化Cipher为加密模式 (Cipher.ENCRYPT_MODE)
        cipher.init(Cipher.ENCRYPT_MODE, k);

        // 将原始字符串转换为字节数组，使用UTF-8编码
        byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
        // 执行加密操作
        return cipher.doFinal(contentBytes);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param buff 待转换的字节数组
     * @return 转换后的十六进制字符串
     */
    public static String byte2Hex(byte[] buff) {
        StringBuilder sb = new StringBuilder();
        for (byte b : buff) {
            // 将字节转换为int，然后&0xFF确保得到正数
            String hex = Integer.toHexString(b & 0xFF);
            // 如果十六进制表示只有一位，前面补零
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex.toUpperCase()); // 转换为大写
        }
        return sb.toString();
    }

    /**
     * 将十六进制字符串转换为字节数组
     *
     * @param hex 待转换的十六进制字符串
     * @return 转换后的字节数组，如果输入不合法则返回null
     */
    public static byte[] hex2Byte(String hex) {
        if (hex == null || hex.length() < 1 || hex.length() % 2 != 0) {
            // 输入字符串为空、长度不足或不是偶数，则不合法
            return null;
        }

        byte[] result = new byte[hex.length() / 2];
        for (int i = 0; i < result.length; i++) {
            // 解析高4位
            int high = Character.digit(hex.charAt(i * 2), 16);
            // 解析低4位
            int low = Character.digit(hex.charAt(i * 2 + 1), 16);

            if (high == -1 || low == -1) {
                // 如果字符不是有效的十六进制数字，则返回null
                return null;
            }
            // 组合高低4位
            result[i] = (byte) (high << 4 | low);
        }
        return result;
    }

    /**
     * 将字节数组形式的密钥转换为Java Key对象
     *
     * @param keyBytes 密钥的字节数组
     * @return SecretKeySpec对象
     * @throws Exception 如果密钥创建失败
     */
    public static Key toKey(byte[] keyBytes) throws Exception {
        // 通过SecretKeySpec创建SecretKey，指定算法
        return new SecretKeySpec(keyBytes, ALGORITHM);
    }

    /**
     * 自动生成AES密钥，并进行Base64编码
     *
     * @return Base64编码的AES密钥字符串
     * @throws NoSuchAlgorithmException 如果JCE中不提供AES算法
     */
    public static String getAutoCreateAESKey() throws NoSuchAlgorithmException {
        // 获取AES密钥生成器实例
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
        // 初始化密钥生成器。AES支持128, 192或256位。默认使用128位。
        // 推荐使用SecureRandom来增加随机性。
        kg.init(128, new SecureRandom());
        // 生成SecretKey
        SecretKey sk = kg.generateKey();
        // 获取密钥的原始字节数组
        byte[] b = sk.getEncoded();
        // 将密钥字节数组进行Base64编码，使用 java.util.Base64.getEncoder()
        return Base64.getEncoder().encodeToString(b);
    }

    public static void main(String[] args) {
        try {
            // 1. 自动生成AES密钥
            String aesKey = getAutoCreateAESKey();
            AppConfig.LOGGER.info("生成的AES密钥 (Base64编码): {}", aesKey);

            String originalContent = "这是一段需要加密的中文文本！Hello World! 12345.";
            AppConfig.LOGGER.info("原始内容: {}", originalContent);

            // 2. 使用生成的密钥进行加密
            String encryptedHex = encrypt2Hex(originalContent, aesKey);
            AppConfig.LOGGER.info("加密后的内容 (Hex): {}", encryptedHex);

            // 3. 使用相同的密钥进行解密
            String decryptedContent = decryptByHex(encryptedHex, aesKey);
            AppConfig.LOGGER.info("解密后的内容: {}", decryptedContent);

            // 4. 验证加密解密是否一致
            if (originalContent.equals(decryptedContent)) {
                AppConfig.LOGGER.info("加密解密验证成功！");
            } else {
                AppConfig.LOGGER.info("加密解密验证失败！");
            }

            // --- 尝试使用固定的短密钥 (不推荐用于生产环境，仅为测试演示) ---
            AppConfig.LOGGER.info("\n--- 使用固定密钥演示 ---");
            // 注意: 固定密钥的Base64解码后长度必须是16, 24, 32字节 (对应128, 192, 256位)
            // 这是一个随机生成的16字节密钥的Base64编码，直接硬编码，实际应用中应避免
            String fixedKeyBase64 = "yL4k/J11mR82tH+a+3M69g=="; // 这是一个随机生成的16字节密钥的Base64编码

            AppConfig.LOGGER.info("固定密钥 (Base64编码): {}", fixedKeyBase64);
            String fixedContent = "测试固定密钥加密解密。";
            AppConfig.LOGGER.info("原始固定内容: {}", fixedContent);

            String fixedEncryptedHex = encrypt2Hex(fixedContent, fixedKeyBase64);
            AppConfig.LOGGER.info("固定密钥加密后的内容 (Hex): {}", fixedEncryptedHex);

            String fixedDecryptedContent = decryptByHex(fixedEncryptedHex, fixedKeyBase64);
            AppConfig.LOGGER.info("固定密钥解密后的内容: {}", fixedDecryptedContent);

            if (fixedContent.equals(fixedDecryptedContent)) {
                AppConfig.LOGGER.info("固定密钥加密解密验证成功！");
            } else {
                AppConfig.LOGGER.info("固定密钥加密解密验证失败！");
            }

        } catch (NoSuchAlgorithmException e) {
            AppConfig.LOGGER.error("错误：不支持的加密算法。{}", e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            AppConfig.LOGGER.error("加密解密过程中发生错误：{}", e.getMessage());
            e.printStackTrace();
        }
    }
}
