package com.fs.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

/**
 * 红杉健康开放平台加解密工具类
 * 遵循文档规则：AES-256-CBC加密内容 + RSA加密AES密钥 + MD5签名
 */
public class RedwoodCryptoUtil {

    // 加密算法配置（与文档一致）
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String AES_KEY_ALGORITHM = "AES";
    private static final int AES_KEY_LENGTH = 256;
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final String RSA_KEY_ALGORITHM = "RSA";
    private static final String SIGN_ALGORITHM = "MD5";

    // 配置参数（需根据实际环境替换）
    private final String appSecret; // 平台提供的应用秘钥（作为AES初始化向量IV）
    private final String platformPublicKey; // 红杉平台RSA公钥（加密AES密钥用）
    private final String thirdPrivateKey; // 三方平台RSA私钥（解密响应密钥用）

    /**
     * 构造函数：初始化配置参数
     *
     * @param appSecret         平台应用秘钥（文档中appsecret）
     * @param platformPublicKey 红杉平台RSA公钥（Base64编码）
     * @param thirdPrivateKey   三方平台RSA私钥（Base64编码）
     */
    public RedwoodCryptoUtil(String appSecret, String platformPublicKey, String thirdPrivateKey) {
        this.appSecret = appSecret;
        this.platformPublicKey = platformPublicKey;
        this.thirdPrivateKey = thirdPrivateKey;
    }

    /**
     * 加密请求参数：生成接口所需的content、key、sign
     *
     * @param plainParam 明文请求参数（Map格式）
     * @return 加密后的请求参数Map（包含content、key、sign）
     * @throws Exception 加密异常
     */
    public Map<String, String> encryptRequest(Map<String, Object> plainParam) throws Exception {
        // 1. 参数按ASCII码排序并转为JSON字符串（不转义Unicode）
        Map<String, Object> sortedMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        sortedMap.putAll(plainParam);
        String contentStr = new String(
                JSON.toJSONBytes(sortedMap, SerializerFeature.BrowserCompatible)
        );

        // 2. 生成32位随机AES密钥（randStr）
        String aesKey = generateRandomAesKey();

        // 3. AES-256-CBC加密contentStr（IV为appSecret）
        String encryptedContent = aesEncrypt(contentStr, aesKey, appSecret);

        // 4. MD5生成签名（对原始contentStr）
        String sign = generateSign(contentStr);

        // 5. 用平台公钥加密AES密钥（RSA-PKCS1-SHA256）
        String encryptedAesKey = rsaEncrypt(aesKey, platformPublicKey);

        // 6. 返回加密结果（Base64编码后）
        Map<String, String> encryptedParam = new HashMap<>();
        encryptedParam.put("content", Base64.encodeBase64String(encryptedContent.getBytes()));
        encryptedParam.put("key", Base64.encodeBase64String(encryptedAesKey.getBytes()));
        encryptedParam.put("sign", sign);
        return encryptedParam;
    }

    /**
     * 解密响应参数：从content、key、sign中还原明文
     *
     * @param encryptedResponse 加密响应参数（包含content、key、sign）
     * @return 明文响应结果（Map格式）
     * @throws Exception 解密异常
     */
    public Map<String, Object> decryptResponse(Map<String, String> encryptedResponse) throws Exception {
        // 1. 提取加密字段并Base64解码
        String encryptedContent = new String(Base64.decodeBase64(encryptedResponse.get("content")));
        String encryptedAesKey = new String(Base64.decodeBase64(encryptedResponse.get("key")));
        String sign = encryptedResponse.get("sign");

        // 2. 用三方私钥解密AES密钥
        String aesKey = rsaDecrypt(encryptedAesKey, thirdPrivateKey);

        // 3. AES-256-CBC解密content（IV为appSecret）
        String contentStr = aesDecrypt(encryptedContent, aesKey, appSecret);

        // 4. 验证签名（防止数据篡改）
        if (!verifySign(contentStr, sign)) {
            throw new SecurityException("签名验证失败，数据可能被篡改");
        }

        // 5. 解析JSON为Map返回
        return JSON.parseObject(contentStr, Map.class);
    }

    /**
     * AES加密（AES-256-CBC）
     */
    private String aesEncrypt(String content, String key, String iv) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), AES_KEY_ALGORITHM);
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encryptedBytes = cipher.doFinal(content.getBytes("UTF-8"));
        return Base64.encodeBase64String(encryptedBytes);
    }

    /**
     * AES解密（AES-256-CBC）
     */
    private String aesDecrypt(String encryptedContent, String key, String iv) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), AES_KEY_ALGORITHM);
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decryptedBytes = cipher.doFinal(Base64.decodeBase64(encryptedContent));
        return new String(decryptedBytes, "UTF-8");
    }

    /**
     * RSA加密（用公钥加密AES密钥）
     */
    private String rsaEncrypt(String content, String publicKeyStr) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
        PublicKey publicKey = KeyFactory.getInstance(RSA_KEY_ALGORITHM).generatePublic(keySpec);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(content.getBytes("UTF-8"));
        return Base64.encodeBase64String(encryptedBytes);
    }

    /**
     * RSA解密（用私钥解密AES密钥）
     */
    private String rsaDecrypt(String encryptedContent, String privateKeyStr) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
        PrivateKey privateKey = KeyFactory.getInstance(RSA_KEY_ALGORITHM).generatePrivate(keySpec);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(Base64.decodeBase64(encryptedContent));
        return new String(decryptedBytes, "UTF-8");
    }

    /**
     * 生成MD5签名
     */
    private String generateSign(String content) throws Exception {
        MessageDigest md5 = MessageDigest.getInstance(SIGN_ALGORITHM);
        byte[] signBytes = md5.digest(content.getBytes("UTF-8"));
        return bytesToHex(signBytes);
    }

    /**
     * 验证MD5签名
     */
    private boolean verifySign(String content, String sign) throws Exception {
        String generatedSign = generateSign(content);
        return generatedSign.equalsIgnoreCase(sign);
    }

    /**
     * 生成32位随机AES密钥（字母+数字）
     */
    private String generateRandomAesKey() {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder(32);
        Random random = new SecureRandom();
        for (int i = 0; i < 32; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }

    /**
     * 字节数组转16进制字符串
     */
    private String bytesToHex(byte[] bytes) {
        StringBuilder hex = new StringBuilder();
        for (byte b : bytes) {
            String hexStr = Integer.toHexString(b & 0xFF);
            if (hexStr.length() == 1) {
                hex.append("0");
            }
            hex.append(hexStr);
        }
        return hex.toString();
    }

    /**
     * 生成RSA密钥对，用于platformPublicKey和thirdPrivateKey
     */
    public static void generateRSAKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048); // 使用2048位密钥长度
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 获取Base64编码的公钥和私钥
        String publicKeyStr = Base64.encodeBase64String(publicKey.getEncoded());
        String privateKeyStr = Base64.encodeBase64String(privateKey.getEncoded());

        System.out.println("公钥 (platformPublicKey):");
        System.out.println(wrapPublicKey(publicKeyStr));
        System.out.println();
        System.out.println("私钥 (thirdPrivateKey):");
        System.out.println(privateKeyStr);
    }

    /**
     * 将公钥包装成PEM格式
     */
    private static String wrapPublicKey(String publicKey) {
        return "-----BEGIN PUBLIC KEY-----\n" +
                splitLines(publicKey) +
                "\n-----END PUBLIC KEY-----";
    }

    /**
     * 将长Base64字符串按64字符分行
     */
    private static String splitLines(String base64Str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < base64Str.length(); i += 64) {
            if (sb.length() > 0) sb.append("\n");
            sb.append(base64Str.substring(i, Math.min(i + 64, base64Str.length())));
        }
        return sb.toString();
    }

    // ------------------------------ 测试示例 ------------------------------
    public static void main(String[] args) throws Exception {
        // 1. 配置参数（替换为文档中的测试参数或实际环境参数）
        String appSecret = "uuRKVwbfSutCpFTv"; // 文档中测试appsecret
        String platformPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk2oCpi9eSMqcmqO3rrMN\n" +
                "b9fqEFMckcRkU520PXyxFalzA2mfLNgNPe8TB9mBSqn7xPxLBBBOSaFwEAeAAs4E\n" +
                "AojMVilbfrTXJh3ucyKlGvTpX3lMKgJaYG7asEzKVbw5V4j8oTBtNh3s20jP7zBm\n" +
                "Y61opsLTIW0qiuvMxezJS8wHc6ajY99RHWBASd3AGozsc3cFLSgIUyh2BhcbB2l7\n" +
                "V8UyDQj7+QI1BwNpkvGxYhP0DF4Yu7buaaf61gygkeeOZ/8JOjcDWBfVB6Q6wEja\n" +
                "os0E9U+rYXN6v90va1wrRp+zRev4sMBWesvwc6uzcuYO/RfSJ19FDMUreCScm8tk\n" +
                "PQIDAQAB"; // 文档中测试红杉密钥-公钥
        String thirdPrivateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCTagKmL15Iypyao7eusw1v1+oQUxyRxGRTnbQ9fLEVqXMDaZ8s2A097xMH2YFKqfvE/EsEEE5JoXAQB4ACzgQCiMxWKVt+tNcmHe5zIqUa9OlfeUwqAlpgbtqwTMpVvDlXiPyhMG02HezbSM/vMGZjrWimwtMhbSqK68zF7MlLzAdzpqNj31EdYEBJ3cAajOxzdwUtKAhTKHYGFxsHaXtXxTINCPv5AjUHA2mS8bFiE/QMXhi7tu5pp/rWDKCR545n/wk6NwNYF9UHpDrASNqizQT1T6thc3q/3S9rXCtGn7NF6/iwwFZ6y/Bzq7Ny5g79F9InX0UMxSt4JJyby2Q9AgMBAAECggEAEqfp6eo4vnGV3CQ4DM3wN2VV4/cAuJnoMITW2Kk9KAan3ZiyYlR9aIcnG2k1aaOVj1p2i+8cWUkrC3xHgRNdgoyZf5YAVErCp7pGASAzUPQJzOFm+DIQCgA9gO5W9P67Kw7VGfks+RpUbXQLjLPNYXQCuIgTfDl6ltY8the/ae4Y/a4dyhBhQ+Q/sygACk/Woiq7B78pc/qCaeMyZyik42aVuC7ZMuIgzERSOBFDrerI/upBWmLE4faeUk4h/PE1Hrj+H2RJ9aM5j4Idn/AJ4H4r8TjzT5m+ldQBfErs37HAVbyP1lQJjmO+VBBvqFchGNDtU1yGIRpxfU5mJI5dQQKBgQDRFPe+IKsheKNF2z0EUke/hU+XIDNc3Qwvp+2ok78G3LiKLRM61II/k+N0PLmJii0JEjqF0figj83Cyr4nnbhymOKIIplftgv085E1ed6QH0m54AwJBCLLA6gHiHin1t21Xh7o38FF6pHQ6EnQjfnVCODkTKxQEihvV3oAv/UBeQKBgQC0fnDPZ29YcIdI2W6xteDFaBfWLTw9usHDu2NnZBPEa+E5Whvcnw6xCgYEI+yasGEt9wOG6tnMEaxIMHRtn7LXaa7nrYxvqE5yTCLpjle3NM3KJRoCxZvOzJwlGWKFRPVpxBe1Sm0DB/IfTbBqzYCVkKQgpnqcpyI91TvxBL/r5QKBgA/bETaf75poNamUiLoNK1fA2lpRnNOMB+KNT56bJb91eaEw7eZmO0JrCrLD8CYYDnZDpaCEXeB/R1FgYq9KbLR0F6nPReZWPe3jkr2FcnVnigXIkeEVKTZQHqwDk3LW/pVEf/+VCGku8sPu+boRKkMXm0Z08hRYbCyVa7Em3YOxAoGAOomzfqC2TQGZ7reOHha1wnBjIrRjEEYsp5VzxMmBW7f9QMOHu8LeWe69SsR37Sd9LRIq06wBXRzyOit050TfFNwSvNLddC0q3AjzXbormqCGiaQEzpdWU/iqP6H/AOf/jADsC4EK3+vIy/w/VjQ2GsvhXzF/HKVcBp/Mo/t9Xz0CgYACKTI8f7z43g6MHy0+QOYBJ4BBDS8SzhLdNIXoUnc4O8kySTospxNVRzZGUMKJ4R8T7bpfR+50H6nCxBZo125eD4lcMHL3Dd/JwabKSer7Nzjt7+UMbgncQIs3m9FjtP1rvYuHvHI7RbxFH+hrYVWMKysWpbS9xtMThF9BosmufA=="; // 文档中测试三方密钥-私钥

        // 2. 创建工具类实例
        RedwoodCryptoUtil cryptoUtil = new RedwoodCryptoUtil(appSecret, platformPublicKey, thirdPrivateKey);

        // 3. 加密请求参数示例（模拟购药问诊申请参数）
        Map<String, Object> plainParam = new HashMap<>();
        plainParam.put("prescription_type", 1);
        plainParam.put("register_type", "picture");
        plainParam.put("union_code", "TEST20250819001");
        // 其他参数按接口要求补充...

        Map<String, String> encryptedParam = cryptoUtil.encryptRequest(plainParam);
        System.out.println("加密后的请求参数：" + encryptedParam);

        // 4. 解密响应参数示例（模拟接口返回的加密数据）
        Map<String, String> mockEncryptedResponse = new HashMap<>();
        mockEncryptedResponse.put("content", "加密后的content");
        mockEncryptedResponse.put("key", "加密后的key");
        mockEncryptedResponse.put("sign", "加密后的sign");

        Map<String, Object> plainResponse = cryptoUtil.decryptResponse(mockEncryptedResponse);
        System.out.println("解密后的响应结果：" + plainResponse);
    }
}