package cn.hztech.sdk.crypto.sm4;

import cn.hztech.sdk.exception.CryptoException;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

/**
 * SM4对称加密工具类
 *
 * 功能：
 * - generateKey: 生成随机SM4密钥
 * - encrypt: 使用SM4加密数据（CBC模式，包含IV）
 * - decrypt: 使用SM4解密数据（CBC模式，包含IV）
 */
@Slf4j
public class SM4Util {

    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    private static final String ALGORITHM = "SM4";
    private static final String TRANSFORMATION = "SM4/CBC/PKCS7Padding";
    private static final int KEY_SIZE = 128;
    private static final int IV_SIZE = 16;

    /**
     * 生成随机SM4密钥
     *
     * @return Base64编码的密钥
     */
    public String generateKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM, "BC");
            keyGenerator.init(KEY_SIZE);
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            log.error("生成SM4密钥失败", e);
            throw new CryptoException("生成SM4密钥失败: " + e.getMessage(), e);
        }
    }

    /**
     * SM4加密
     *
     * @param data 明文数据
     * @param keyBase64 Base64编码的密钥
     * @return Base64编码的密文（包含IV）
     */
    public String encrypt(String data, String keyBase64) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION, "BC");

            // 生成随机IV
            byte[] iv = new byte[IV_SIZE];
            SecureRandom random = new SecureRandom();
            random.nextBytes(iv);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

            // 将IV和密文拼接后返回
            byte[] result = new byte[iv.length + encrypted.length];
            System.arraycopy(iv, 0, result, 0, iv.length);
            System.arraycopy(encrypted, 0, result, iv.length, encrypted.length);

            return Base64.getEncoder().encodeToString(result);

        } catch (Exception e) {
            log.error("SM4加密失败", e);
            throw new CryptoException("SM4加密失败: " + e.getMessage(), e);
        }
    }

    /**
     * SM4解密
     *
     * @param encryptedDataBase64 Base64编码的密文（包含IV）
     * @param keyBase64 Base64编码的密钥
     * @return 明文数据
     */
    public String decrypt(String encryptedDataBase64, String keyBase64) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);

            byte[] encryptedData = Base64.getDecoder().decode(encryptedDataBase64);

            // 提取IV（前16字节）
            byte[] iv = new byte[IV_SIZE];
            System.arraycopy(encryptedData, 0, iv, 0, IV_SIZE);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            // 提取密文（16字节之后）
            byte[] encrypted = new byte[encryptedData.length - IV_SIZE];
            System.arraycopy(encryptedData, IV_SIZE, encrypted, 0, encrypted.length);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION, "BC");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] decrypted = cipher.doFinal(encrypted);

            return new String(decrypted, StandardCharsets.UTF_8);

        } catch (Exception e) {
            log.error("SM4解密失败", e);
            throw new CryptoException("SM4解密失败: " + e.getMessage(), e);
        }
    }
}
