package org.xyzh.common.utils.crypto;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

/**
 * AES-256-GCM 敏感数据加密工具类
 * 用于加密手机号、身份证号等敏感信息
 * 
 * @author yslg
 * @since 2025-12-05
 */
@Component
public class AesEncryptUtil {

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    private static final int KEY_SIZE = 256; // AES-256
    private static final int GCM_IV_LENGTH = 12; // GCM 推荐 IV 长度
    private static final int GCM_TAG_LENGTH = 128; // GCM 认证标签长度

    private SecretKey secretKey;

    /**
     * 从配置文件读取密钥，如果没有则生成新密钥
     */
    public AesEncryptUtil(@Value("${security.aes.secret-key:}") String secretKeyString) {
        try {
            if (secretKeyString == null || secretKeyString.isEmpty()) {
                // 生产环境应该从配置中心或密钥管理系统获取
                this.secretKey = generateKey();
                System.err.println("警告: 未配置 AES 密钥，使用临时生成的密钥。生产环境请配置 security.aes.secret-key");
            } else {
                byte[] decodedKey = Base64.getDecoder().decode(secretKeyString);
                if (decodedKey.length != 32) {
                    throw new IllegalArgumentException("AES-256 密钥长度必须是 32 字节，当前: " + decodedKey.length);
                }
                this.secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, ALGORITHM);
                System.out.println("✓ AES-256 加密工具初始化成功");
            }
        } catch (Exception e) {
            System.err.println("❌ AES 密钥初始化失败: " + e.getMessage());
            // 生成临时密钥以避免启动失败
            this.secretKey = generateKey();
            System.err.println("已生成临时密钥，请尽快配置正确的 security.aes.secret-key");
        }
    }

    /**
     * 生成 AES-256 密钥
     */
    public static SecretKey generateKey() {
        try {
            KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
            keyGen.init(KEY_SIZE, new SecureRandom());
            return keyGen.generateKey();
        } catch (Exception e) {
            throw new RuntimeException("生成 AES 密钥失败", e);
        }
    }

    /**
     * 将密钥转换为 Base64 字符串（用于配置）
     */
    public static String keyToString(SecretKey key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /**
     * 加密字符串
     * 
     * @param plaintext 明文
     * @return Base64 编码的密文（包含 IV）
     */
    public String encrypt(String plaintext) {
        if (plaintext == null || plaintext.isEmpty()) {
            return plaintext;
        }

        try {
            // 生成随机 IV
            byte[] iv = new byte[GCM_IV_LENGTH];
            new SecureRandom().nextBytes(iv);

            // 初始化加密器
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

            // 加密
            byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

            // 将 IV 和密文组合在一起：[IV(12字节)][密文]
            ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + ciphertext.length);
            byteBuffer.put(iv);
            byteBuffer.put(ciphertext);

            // Base64 编码
            return Base64.getEncoder().encodeToString(byteBuffer.array());
        } catch (Exception e) {
            throw new RuntimeException("AES 加密失败", e);
        }
    }

    /**
     * 解密字符串
     * 
     * @param ciphertext Base64 编码的密文（包含 IV）
     * @return 明文
     */
    public String decrypt(String ciphertext) {
        if (ciphertext == null || ciphertext.isEmpty()) {
            return ciphertext;
        }

        try {
            // Base64 解码
            byte[] decoded = Base64.getDecoder().decode(ciphertext);

            // 提取 IV 和密文
            ByteBuffer byteBuffer = ByteBuffer.wrap(decoded);
            byte[] iv = new byte[GCM_IV_LENGTH];
            byteBuffer.get(iv);
            byte[] ciphertextBytes = new byte[byteBuffer.remaining()];
            byteBuffer.get(ciphertextBytes);

            // 初始化解密器
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);

            // 解密
            byte[] plaintext = cipher.doFinal(ciphertextBytes);
            return new String(plaintext, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES 解密失败", e);
        }
    }

    /**
     * 加密手机号（保留前3后4位）
     * 例如：13812345678 -> 138****5678
     * 实际存储：加密后的完整手机号
     */
    public String encryptPhone(String phone) {
        return encrypt(phone);
    }

    /**
     * 解密手机号
     */
    public String decryptPhone(String encryptedPhone) {
        return decrypt(encryptedPhone);
    }

    /**
     * 加密身份证号（保留前6后4位）
     * 例如：110101199001011234 -> 110101********1234
     * 实际存储：加密后的完整身份证号
     */
    public String encryptIdCard(String idCard) {
        return encrypt(idCard);
    }

    /**
     * 解密身份证号
     */
    public String decryptIdCard(String encryptedIdCard) {
        return decrypt(encryptedIdCard);
    }

    /**
     * 生成手机号Hash（用于数据库查询）
     * 使用SHA-256生成固定Hash，相同手机号总是得到相同Hash
     */
    public static String maskPhone(String phone) {
        if (phone == null || phone.isEmpty()) {
            return phone;
        }
        try {
            java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(phone.getBytes(java.nio.charset.StandardCharsets.UTF_8));
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException("生成手机号Hash失败", e);
        }
    }
    
    /**
     * 脱敏显示手机号（用于前端显示）
     */
    public static String maskPhoneDisplay(String phone) {
        if (phone == null || phone.length() < 11) {
            return phone;
        }
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }

    /**
     * 脱敏显示身份证号
     */
    public static String maskIdCard(String idCard) {
        if (idCard == null || idCard.length() < 18) {
            return idCard;
        }
        return idCard.substring(0, 6) + "********" + idCard.substring(14);
    }

    public static void main(String[] args) {
        AesEncryptUtil aesEncryptUtil = new AesEncryptUtil("MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=");
        String phone = "17857100376";
        
        // 测试加密（每次都不同，不能用于查询）
        String encryptedPhone1 = aesEncryptUtil.encryptPhone(phone);
        String encryptedPhone2 = aesEncryptUtil.encryptPhone(phone);
        System.out.println("第一次加密: " + encryptedPhone1);
        System.out.println("第二次加密: " + encryptedPhone2);
        System.out.println("两次加密相同? " + encryptedPhone1.equals(encryptedPhone2));
        
        // 测试Hash（用于查询，相同手机号总是得到相同Hash）
        String hash1 = AesEncryptUtil.maskPhone(phone);
        String hash2 = AesEncryptUtil.maskPhone(phone);
        System.out.println("\n第一次Hash: " + hash1);
        System.out.println("第二次Hash: " + hash2);
        System.out.println("两次Hash相同? " + hash1.equals(hash2));
        
        // 测试脱敏显示
        System.out.println("\n脱敏显示: " + AesEncryptUtil.maskPhoneDisplay(phone));
    }
}
