package com.fs.company.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * 加密解密工具类
 * 用于接口入参解析、返回结果加解密处理
 *
 */
public class CryptoUtil {

    private static final Logger log = LoggerFactory.getLogger(CryptoUtil.class);

    public static void main(String[] args) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name", "MixLiu");
        jsonObject.put("age", 18);
        jsonObject.put("sex", "男");
        jsonObject.put("occupation","engineer");
        String encrypt = encrypt(jsonObject.toJSONString());
        System.out.println(encrypt);
        String decrypt = decrypt(encrypt);
        System.out.println(decrypt);
        System.out.println(JSONObject.parse(decrypt));
    }
    // ==================== 秘钥配置 ====================
    /**
     * AES加密秘钥
     * 【重要】请根据实际业务需求修改此秘钥
     * 秘钥长度必须为16位（AES-128）、24位（AES-192）或32位（AES-256）
     * 当前使用AES-128，秘钥长度为16位
     */
    private static final String AES_SECRET_KEY = "FsCmp@nyK3y!2026";

    /**
     * 备用秘钥（用于秘钥轮换场景）
     * 【重要】生产环境请修改为不同的秘钥
     */
    private static final String AES_BACKUP_KEY = "BkFC0mp@nyK3y!26";

    /**
     * AES加密算法/模式/填充方式
     * AES/ECB/PKCS5Padding：AES加密，ECB模式，PKCS5填充
     */
    private static final String AES_ALGORITHM = "AES/ECB/PKCS5Padding";

    /**
     * AES算法名称
     */
    private static final String AES_KEY_ALGORITHM = "AES";

    // ==================== 加密方法 ====================

    /**
     * AES加密
     * 用于加密入参或返回结果
     *
     * @param plainText 明文
     * @return Base64编码的密文，加密失败返回null
     */
    public static String encrypt(String plainText) {
        return encrypt(plainText, AES_SECRET_KEY);
    }

    /**
     * AES加密（使用指定秘钥）
     *
     * @param plainText 明文
     * @param secretKey 秘钥
     * @return Base64编码的密文，加密失败返回null
     */
    public static String encrypt(String plainText, String secretKey) {
        if (plainText == null || secretKey == null) {
            log.warn("加密参数不能为空");
            return null;
        }
        try {
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), AES_KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            log.error("AES加密失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 加密入参
     * 将原始入参字符串加密后返回
     *
     * @param inputParam 原始入参
     * @return 加密后的入参字符串
     */
    public static String encryptInput(String inputParam) {
        log.debug("加密入参");
        return encrypt(inputParam);
    }

    /**
     * 加密返回结果
     * 将返回结果对象转换为JSON字符串后加密
     *
     * @param result 返回结果对象
     * @return 加密后的结果字符串
     */
    public static String encryptResult(Object result) {
        if (result == null) {
            return null;
        }
        String jsonStr;
        if (result instanceof String) {
            jsonStr = (String) result;
        } else {
            jsonStr = JSON.toJSONString(result);
        }
        log.debug("加密返回结果");
        return encrypt(jsonStr);
    }

    // ==================== 解密方法 ====================

    /**
     * AES解密
     * 用于解密入参或返回结果
     *
     * @param encryptedText Base64编码的密文
     * @return 解密后的明文，解密失败返回null
     */
    public static String decrypt(String encryptedText) {
        return decrypt(encryptedText, AES_SECRET_KEY);
    }

    /**
     * AES解密（使用指定秘钥）
     *
     * @param encryptedText Base64编码的密文
     * @param secretKey     秘钥
     * @return 解密后的明文，解密失败返回null
     */
    public static String decrypt(String encryptedText, String secretKey) {
        if (encryptedText == null || secretKey == null) {
            log.warn("解密参数不能为空");
            return null;
        }
        try {
            SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), AES_KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("AES解密失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 解密入参
     * 将加密的入参字符串解密
     *
     * @param encryptedInput 加密的入参
     * @return 解密后的入参字符串
     */
    public static String decryptInput(String encryptedInput) {
        log.debug("解密入参");
        return decrypt(encryptedInput);
    }

    /**
     * 解密返回结果
     * 将加密的返回结果解密
     *
     * @param encryptedResult 加密的返回结果
     * @return 解密后的结果字符串
     */
    public static String decryptResult(String encryptedResult) {
        log.debug("解密返回结果");
        return decrypt(encryptedResult);
    }

    // ==================== 解析方法 ====================

    /**
     * 解析入参（解密后解析为JSON对象）
     * 先解密入参，再将解密后的字符串解析为JSONObject
     *
     * @param encryptedInput 加密的入参
     * @return 解析后的JSONObject，解析失败返回null
     */
    public static JSONObject parseInput(String encryptedInput) {
        String decryptedStr = decryptInput(encryptedInput);
        if (decryptedStr == null) {
            log.warn("入参解密失败，无法解析");
            return null;
        }
        try {
            return JSON.parseObject(decryptedStr);
        } catch (Exception e) {
            log.error("入参JSON解析失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 解析入参（解密后解析为指定类型对象）
     * 先解密入参，再将解密后的字符串解析为指定类型的对象
     *
     * @param encryptedInput 加密的入参
     * @param clazz          目标类型
     * @param <T>            泛型类型
     * @return 解析后的对象，解析失败返回null
     */
    public static <T> T parseInput(String encryptedInput, Class<T> clazz) {
        String decryptedStr = decryptInput(encryptedInput);
        if (decryptedStr == null) {
            log.warn("入参解密失败，无法解析");
            return null;
        }
        try {
            return JSON.parseObject(decryptedStr, clazz);
        } catch (Exception e) {
            log.error("入参解析为{}失败: {}", clazz.getSimpleName(), e.getMessage(), e);
            return null;
        }
    }

    /**
     * 解析返回结果（解密后解析为JSON对象）
     * 先解密返回结果，再将解密后的字符串解析为JSONObject
     *
     * @param encryptedResult 加密的返回结果
     * @return 解析后的JSONObject，解析失败返回null
     */
    public static JSONObject parseResult(String encryptedResult) {
        String decryptedStr = decryptResult(encryptedResult);
        if (decryptedStr == null) {
            log.warn("返回结果解密失败，无法解析");
            return null;
        }
        try {
            return JSON.parseObject(decryptedStr);
        } catch (Exception e) {
            log.error("返回结果JSON解析失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 解析返回结果（解密后解析为指定类型对象）
     * 先解密返回结果，再将解密后的字符串解析为指定类型的对象
     *
     * @param encryptedResult 加密的返回结果
     * @param clazz           目标类型
     * @param <T>             泛型类型
     * @return 解析后的对象，解析失败返回null
     */
    public static <T> T parseResult(String encryptedResult, Class<T> clazz) {
        String decryptedStr = decryptResult(encryptedResult);
        if (decryptedStr == null) {
            log.warn("返回结果解密失败，无法解析");
            return null;
        }
        try {
            return JSON.parseObject(decryptedStr, clazz);
        } catch (Exception e) {
            log.error("返回结果解析为{}失败: {}", clazz.getSimpleName(), e.getMessage(), e);
            return null;
        }
    }

    // ==================== 秘钥轮换相关 ====================

    /**
     * 使用备用秘钥解密（用于秘钥轮换场景）
     * 先尝试主秘钥解密，失败后尝试备用秘钥
     *
     * @param encryptedText 加密文本
     * @return 解密后的明文
     */
    public static String decryptWithFallback(String encryptedText) {
        String result = decrypt(encryptedText, AES_SECRET_KEY);
        if (result == null) {
            log.info("主秘钥解密失败，尝试使用备用秘钥");
            result = decrypt(encryptedText, AES_BACKUP_KEY);
        }
        return result;
    }

    // ==================== 工具方法 ====================

    /**
     * 验证秘钥长度是否有效
     *
     * @param key 秘钥
     * @return 是否有效
     */
    public static boolean isValidKeyLength(String key) {
        if (key == null) {
            return false;
        }
        int len = key.getBytes(StandardCharsets.UTF_8).length;
        return len == 16 || len == 24 || len == 32;
    }

    /**
     * 获取当前使用的秘钥长度
     *
     * @return 秘钥长度
     */
    public static int getKeyLength() {
        return AES_SECRET_KEY.getBytes(StandardCharsets.UTF_8).length;
    }
}
