package com.admin.common.utils;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES加密工具类
 * 使用AES-256-GCM模式，与Go端保持兼容
 */
@Slf4j
public class AESCrypto {
    
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    private static final int GCM_IV_LENGTH = 12; // GCM推荐的IV长度
    private static final int GCM_TAG_LENGTH = 16; // GCM认证标签长度
    
    private final SecretKeySpec secretKey;
    private final SecureRandom secureRandom;
    
    /**
     * 构造函数
     * @param secret 密钥字符串，将使用SHA-256转换为32字节密钥
     */
    public AESCrypto(String secret) {
        if (secret == null || secret.isEmpty()) {
            throw new IllegalArgumentException("密钥不能为空");
        }
        
        try {
            // 使用SHA-256将密码转换为32字节密钥，与Go端保持一致
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
            byte[] keyBytes = sha256.digest(secret.getBytes(StandardCharsets.UTF_8));
            this.secretKey = new SecretKeySpec(keyBytes, ALGORITHM);
            this.secureRandom = new SecureRandom();
            
        } catch (Exception e) {
            log.info("AES加密器初始化失败", e);
            throw new RuntimeException("AES加密器初始化失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 加密数据
     * @param data 要加密的原始数据
     * @return Base64编码的加密数据，格式为: nonce + ciphertext
     */
    public String encrypt(byte[] data) {
        if (data == null || data.length == 0) {
            throw new IllegalArgumentException("待加密数据不能为空");
        }
        
        try {
            // 生成随机IV（nonce）
            byte[] iv = new byte[GCM_IV_LENGTH];
            secureRandom.nextBytes(iv);
            
            // 创建GCM参数规范
            GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            
            // 初始化Cipher
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmSpec);
            
            // 加密数据
            byte[] ciphertext = cipher.doFinal(data);
            
            // 组合IV + ciphertext，与Go端格式保持一致
            ByteBuffer buffer = ByteBuffer.allocate(iv.length + ciphertext.length);
            buffer.put(iv);
            buffer.put(ciphertext);
            
            // 返回Base64编码结果
            return Base64.getEncoder().encodeToString(buffer.array());
            
        } catch (Exception e) {
            log.info("数据加密失败", e);
            throw new RuntimeException("数据加密失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 加密字符串
     * @param data 要加密的字符串
     * @return Base64编码的加密数据
     */
    public String encrypt(String data) {
        if (data == null) {
            throw new IllegalArgumentException("待加密字符串不能为空");
        }
        return encrypt(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * 解密数据
     * @param encryptedData Base64编码的加密数据
     * @return 解密后的原始数据
     */
    public byte[] decrypt(String encryptedData) {
        if (encryptedData == null || encryptedData.isEmpty()) {
            throw new IllegalArgumentException("加密数据不能为空");
        }
        
        try {
            // Base64解码
            byte[] encrypted = Base64.getDecoder().decode(encryptedData);
            
            if (encrypted.length < GCM_IV_LENGTH) {
                throw new IllegalArgumentException("加密数据长度不足");
            }
            
            // 分离IV和密文
            ByteBuffer buffer = ByteBuffer.wrap(encrypted);
            byte[] iv = new byte[GCM_IV_LENGTH];
            buffer.get(iv);
            
            byte[] ciphertext = new byte[buffer.remaining()];
            buffer.get(ciphertext);
            
            // 创建GCM参数规范
            GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            
            // 初始化Cipher
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec);
            
            // 解密数据
            return cipher.doFinal(ciphertext);
            
        } catch (Exception e) {
            log.info("数据解密失败", e);
            throw new RuntimeException("数据解密失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 解密字符串
     * @param encryptedData Base64编码的加密数据
     * @return 解密后的字符串
     */
    public String decryptString(String encryptedData) {
        byte[] decrypted = decrypt(encryptedData);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    
    /**
     * 创建AES加密器实例
     * @param secret 密钥字符串
     * @return AES加密器实例，如果创建失败返回null
     */
    public static AESCrypto create(String secret) {
        try {
            return new AESCrypto(secret);
        } catch (Exception e) {
            log.info("创建AES加密器失败: {}", e.getMessage());
            return null;
        }
    }
} 