package com.crm.pay.utils;

import org.bouncycastle.asn1.pkcs.RSAPublicKey;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSAIbitUtil {

    private static final String RSA = "RSA";
    private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";

    /**
     * 公钥加密（支持 PKCS1 / X509）
     */
    public static String encryptByPublicKey(String data, String publicKeyPem) throws Exception {
        PublicKey publicKey = loadPublicKey(publicKeyPem);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 私钥解密（PKCS8）
     */
    public static String decryptByPrivateKey(String encryptedBase64, String privateKeyPem) throws Exception {
        PrivateKey privateKey = loadPrivateKey(privateKeyPem);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedBase64));
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * 解析公钥（自动识别 RSA PUBLIC KEY / PUBLIC KEY）
     */
    private static PublicKey loadPublicKey(String key) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        // 统一清洗
        String clean = key
                .replaceAll("-----BEGIN ([A-Z ]*)-----", "")
                .replaceAll("-----END ([A-Z ]*)-----", "")
                .replaceAll("\\s", "");

        byte[] keyBytes = Base64.getDecoder().decode(clean);

        // ===== 1️⃣ 先按 PKCS1 解析 =====
        try {
            RSAPublicKey rsaPublicKey = RSAPublicKey.getInstance(keyBytes);
            RSAPublicKeySpec spec = new RSAPublicKeySpec(
                    rsaPublicKey.getModulus(),
                    rsaPublicKey.getPublicExponent()
            );
            return keyFactory.generatePublic(spec);
        } catch (Exception ignored) {
            // 不是 PKCS1，继续
        }

        // ===== 2️⃣ 再按 X509 解析 =====
        try {
            return keyFactory.generatePublic(
                    new X509EncodedKeySpec(keyBytes)
            );
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "Unsupported public key format (not PKCS1 or X509)", e
            );
        }
    }

    /**
     * 解析私钥（PKCS8）
     */
    private static PrivateKey loadPrivateKey(String key) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        // 统一清洗
        String clean = key
                .replaceAll("-----BEGIN ([A-Z ]*)-----", "")
                .replaceAll("-----END ([A-Z ]*)-----", "")
                .replaceAll("\\s", "");

        byte[] keyBytes = Base64.getDecoder().decode(clean);

        // ===== 1️⃣ 先按 PKCS1 解析 =====
        try {
            org.bouncycastle.asn1.pkcs.RSAPrivateKey rsaPrivateKey =
                    org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(keyBytes);

            RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(
                    rsaPrivateKey.getModulus(),
                    rsaPrivateKey.getPublicExponent(),
                    rsaPrivateKey.getPrivateExponent(),
                    rsaPrivateKey.getPrime1(),
                    rsaPrivateKey.getPrime2(),
                    rsaPrivateKey.getExponent1(),
                    rsaPrivateKey.getExponent2(),
                    rsaPrivateKey.getCoefficient()
            );
            return keyFactory.generatePrivate(spec);

        } catch (Exception ignored) {
            // 不是 PKCS1，继续
        }

        // ===== 2️⃣ 再按 PKCS8 解析 =====
        try {
            return keyFactory.generatePrivate(
                    new PKCS8EncodedKeySpec(keyBytes)
            );
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "Unsupported private key format (not PKCS1 or PKCS8)", e
            );
        }
    }
}