package com.fs.common.utils;

import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 红杉健康平台加解密工具类
 */
public class HsCryptoUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";

    /**
     * 加密方法
     * @param data 待加密的数据对象
     * @param appSecret 应用密钥，用于AES加密的IV
     * @param publicKeyStr RSA公钥（Base64编码）
     * @return 加密结果Map，包含content、key、sign三个字段
     */
    public static Map<String, String> encrypt(JSONObject data, String appSecret, String publicKeyStr) {
        try {
//            公钥解码base64
            String publicKey = new String( Base64.decodeBase64(publicKeyStr), StandardCharsets.UTF_8);
            publicKey = publicKey.replace("-----BEGIN PUBLIC KEY-----\n", "").replace(
                    "\n" +
                            "-----END PUBLIC KEY-----\n", ""
            );
            // 1. 将对象转换为按ASCII码排序的Map

            Map<String, Object> sortedParams = new TreeMap<>();
            /*处理掉空值，否则转jsonString要报错*/
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                if ( entry.getValue() != null && !(entry.getValue() instanceof cn.hutool.json.JSONNull)) {
                    Object processedValue = processNestedObjects(entry.getValue());
                    sortedParams.put(entry.getKey(), processedValue);
                }
            }
            String contentStr = objectMapper.writeValueAsString(sortedParams);
//            // 直接转换 JSONObject 为 Map
//            Map<String, Object> sortedParams = convertToSortedMap(data);
//
//            // 2. 转换为JSON字符串（contentStr）
//            String contentStr = objectMapper.writeValueAsString(sortedParams);

            // 3. 生成32位随机密钥(randStr)
            String randStr = generateRandStr(32);

            // 4. AES-256-CBC加密contentStr
            String encryptedContent = aesEncrypt(contentStr, randStr, appSecret);

            // 5. 使用RSA公钥加密randStr
            String encryptedKey = rsaEncrypt(randStr, publicKey);

            // 6. 对contentStr进行MD5签名
            String sign = DigestUtils.md5Hex(contentStr);

            // 7. 构造返回结果
            Map<String, String> result = new TreeMap<>();
            result.put("content", encryptedContent);
            result.put("key", encryptedKey);
            result.put("sign", sign);

            return result;
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    /**
     * 递归处理嵌套的JSON对象 的jsonNull和null
     */
    private static Object processNestedObjects(Object value) {
        if (value instanceof cn.hutool.json.JSONObject) {
            // 处理嵌套的JSONObject
            cn.hutool.json.JSONObject jsonObj = (cn.hutool.json.JSONObject) value;
            Map<String, Object> nestedMap = new TreeMap<>();
            for (Map.Entry<String, Object> entry : jsonObj.entrySet()) {
                if (entry.getValue() != null && !(entry.getValue() instanceof cn.hutool.json.JSONNull)) {
                    nestedMap.put(entry.getKey(), processNestedObjects(entry.getValue()));
                }
            }
            return nestedMap;
        } else if (value instanceof cn.hutool.json.JSONArray) {
            // 处理JSONArray
            cn.hutool.json.JSONArray jsonArray = (cn.hutool.json.JSONArray) value;
            List<Object> list = new ArrayList<>();
            for (Object item : jsonArray) {
                list.add(processNestedObjects(item));
            }
            return list;
        } else {
            // 基本类型直接返回
            return value;
        }
    }

    /**
     * 将对象转换为按ASCII码排序的Map
     */
    private static Map<String, Object> convertToSortedMap(Object obj) throws Exception {
        Map<String, Object> map = objectMapper.convertValue(obj, Map.class);
        return new TreeMap<>(map);
    }

    /**
     * 生成指定长度的随机字符串
     */
    private static String generateRandStr(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(length);

        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }

    /**
     * AES-256-CBC加密
     */
    private static String aesEncrypt(String content, String randStr, String appSecret) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        SecretKeySpec keySpec = new SecretKeySpec(randStr.getBytes(), "AES");
        // 使用appSecret的前16位作为IV
        IvParameterSpec ivSpec = new IvParameterSpec(appSecret.substring(0, 16).getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(content.getBytes());
        return Base64.encodeBase64String(encrypted);
    }

    /**
     * RSA加密
     */
    private static String rsaEncrypt(String randStr, String publicKey) throws Exception {
        byte[] decodedPublicKey = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedPublicKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] encrypted = cipher.doFinal(randStr.getBytes());
        return Base64.encodeBase64String(encrypted);
    }

    /**
     * 解密方法
     * @param encryptedContent AES加密的内容（Base64编码）
     * @param encryptedKey RSA加密的密钥（Base64编码）
     * @param sign 签名（MD5）
     * @param appSecret 应用密钥，用于AES解密的IV
     * @param privateKeyStr RSA私钥（PEM格式，Base64编码）
     * @return 解密后的原始数据对象
     */
    public static Map<String, Object> decrypt(String encryptedContent,
                                              String encryptedKey,
                                              String sign,
                                              String appSecret,
                                              String privateKeyStr) {
        try {
            // 1. Base64解码私钥字符串，得到PEM格式的私钥
            String privateKeyPEM = new String(
                    Base64.decodeBase64(privateKeyStr),
                    StandardCharsets.UTF_8
            );
            // 1. RSA解密获取AES密钥（randStr）
            String randStr = rsaDecrypt(encryptedKey, privateKeyPEM);

            // 2. AES解密获取contentStr
            String contentStr = aesDecrypt(encryptedContent, randStr, appSecret);

            // 3. 验证签名
            String calculatedSign = DigestUtils.md5Hex(contentStr);
            if (!calculatedSign.equals(sign)) {
                throw new RuntimeException("签名验证失败，数据可能被篡改");
            }

            // 4. 将contentStr解析为Map
            return objectMapper.readValue(contentStr, Map.class);

        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }

    /**
     * 解密并验证的完整方法
     * @param encryptedData 加密数据Map，包含content、key、sign三个字段
     * @param appSecret 应用密钥
     * @param privateKeyStr RSA私钥
     * @return 解密后的原始数据Map
     */
    public static Map<String, Object> decrypt(JsonNode encryptedData,
                                              String appSecret,
                                              String privateKeyStr) {
        return decrypt(
                encryptedData.get("content").asText(),
                encryptedData.get("key").asText(),
                encryptedData.get("sign").asText(),
                appSecret,
                privateKeyStr
        );
    }

    /**
     * RSA解密 - 使用私钥解密AES密钥
     */
    private static String rsaDecrypt(String encryptedKey, String privateKeyStr) throws Exception {
//    String privateKey = new String( Base64.decodeBase64(privateKeyStr), StandardCharsets.UTF_8);

        // 处理PEM格式的私钥
        String privateKeyPEM = privateKeyStr
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");

        byte[] decodedPrivateKey = Base64.decodeBase64(privateKeyPEM);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedPrivateKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte[] encryptedBytes = Base64.decodeBase64(encryptedKey);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * AES-256-CBC解密
     */
    private static String aesDecrypt(String encryptedContent,
                                     String randStr,
                                     String appSecret) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        SecretKeySpec keySpec = new SecretKeySpec(randStr.getBytes(StandardCharsets.UTF_8), "AES");

        // 使用appSecret的前16位作为IV（与加密时一致）
        String iv = appSecret.length() >= 16 ? appSecret.substring(0, 16) : appSecret;
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

        byte[] encryptedBytes = Base64.decodeBase64(encryptedContent);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 验证签名（不进行解密）
     */
    public static boolean verifySignature(String contentStr, String sign) {
        String calculatedSign = DigestUtils.md5Hex(contentStr);
        return calculatedSign.equals(sign);
    }

    /**
     * 单独解密AES密钥（用于调试）
     */
    public static String decryptKeyOnly(String encryptedKey, String privateKeyStr) throws Exception {
        return rsaDecrypt(encryptedKey, privateKeyStr);
    }

    /**
     * 单独解密内容（需要提供AES密钥）
     */
    public static String decryptContentOnly(String encryptedContent,
                                            String randStr,
                                            String appSecret) throws Exception {
        return aesDecrypt(encryptedContent, randStr, appSecret);
    }


//    /**
//     * 解密方法
//     * @param encryptedData 加密的数据Map，包含content、key、sign三个字段
//     * @param appSecret 应用密钥，用于AES解密的IV
//     * @param privateKeyStr RSA私钥（Base64编码）
//     * @return 解密后的原始数据对象
//     */
//    public static Map<String, Object> decrypt(JsonNode encryptedData, String appSecret, String privateKeyStr) {
//        //            私钥解码base64
//    String privateKey = new String( Base64.decodeBase64(privateKeyStr), StandardCharsets.UTF_8);

//        privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----\n", "").replace(
//                "\n" +
//                        "-----END PRIVATE KEY-----", ""
//        );
//        try {
//            String content = String.valueOf(encryptedData.get("content"));
//            String key = String.valueOf(encryptedData.get("key"));
//            String sign = String.valueOf(encryptedData.get("sign"));
//
//            // 1. 使用RSA私钥解密key字段，得到randStr
//            String randStr = rsaDecrypt(key, privateKey);
//
//            // 2. 使用AES-256-CBC解密content字段
//            String decryptedContent = aesDecrypt(content, randStr, appSecret);
//
//            // 3. 验证签名
//            String calculatedSign = DigestUtils.md5Hex(decryptedContent);
//            if (!calculatedSign.equals(sign)) {
//                throw new RuntimeException("签名验证失败");
//            }
//
//            // 4. 将解密后的JSON字符串转换为Map对象
//            @SuppressWarnings("unchecked")
//            Map<String, Object> result = objectMapper.readValue(decryptedContent, Map.class);
//
//            return result;
//        } catch (Exception e) {
//            throw new RuntimeException("解密失败", e);
//        }
//    }
//
//    /**
//     * AES-256-CBC解密
//     */
//    private static String aesDecrypt(String content, String randStr, String appSecret) throws Exception {
//        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
//        SecretKeySpec keySpec = new SecretKeySpec(randStr.getBytes(), "AES");
//        // 使用appSecret的前16位作为IV
//        IvParameterSpec ivSpec = new IvParameterSpec(appSecret.substring(0, 16).getBytes());
//        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
//        byte[] decrypted = cipher.doFinal(Base64.decodeBase64(content));
//        return new String(decrypted);
//    }
//
//    /**
//     * RSA解密
//     */
//    private static String rsaDecrypt(String encryptedKey, String privateKey) throws Exception {
//        byte[] decodedPrivateKey = Base64.decodeBase64(privateKey);
//        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedPrivateKey);
//        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//        PrivateKey privKey = keyFactory.generatePrivate(keySpec);
//
//        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
//        cipher.init(Cipher.DECRYPT_MODE, privKey);
//        byte[] decrypted = cipher.doFinal(Base64.decodeBase64(encryptedKey));
//        return new String(decrypted);
//    }
}
