package com.sunyard.chsm.utils.gm.cert;

import com.sunyard.chsm.utils.gm.GMBaseUtil;
import lombok.SneakyThrows;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Iterator;
import java.util.Map;

public class CommonCertUtils extends GMBaseUtil {
    /**
     * 如果不知道怎么填充names，可以查看org.bouncycastle.asn1.x500.style.BCStyle这个类，
     * names的key值必须是BCStyle.DefaultLookUp中存在的（可以不关心大小写）
     *
     * @param names
     * @return
     * @throws IllegalArgumentException
     */
    public static X500Name buildX500Name(Map<String, String> names) {
        if (names == null || names.size() == 0) {
            throw new IllegalArgumentException("names can not be empty");
        }
        try {
            X500NameBuilder builder = new X500NameBuilder();
            Iterator itr = names.entrySet().iterator();
            BCStyle x500NameStyle = (BCStyle) BCStyle.INSTANCE;
            Map.Entry entry;
            while (itr.hasNext()) {
                entry = (Map.Entry) itr.next();
                ASN1ObjectIdentifier oid = x500NameStyle.attrNameToOID((String) entry.getKey());
                builder.addRDN(oid, (String) entry.getValue());
            }
            return builder.build();
        } catch (Exception ex) {
            throw new IllegalArgumentException(ex.getMessage(), ex);
        }
    }

    @SneakyThrows
    public static String generateP10(String dn, PublicKey pubKey, PrivateKey priKey) {
        X500Name subject = new X500Name(dn);
        JcaPKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, pubKey);
        ContentSigner signer = new JcaContentSignerBuilder("SM3withSM2")
                .setProvider(BC).build(priKey);

        // 生成 P10 证书请求
        PKCS10CertificationRequest csr = csrBuilder.build(signer);

        return writePem(PEMParser.TYPE_CERTIFICATE_REQUEST, csr.getEncoded());
    }

    public static PKCS10CertificationRequest createCSR(X500Name subject, BCECPublicKey pubKey, PrivateKey priKey) throws OperatorCreationException {
        SM2PublicKey sm2SubPub = new SM2PublicKey(pubKey.getAlgorithm(), pubKey);
        PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, sm2SubPub);
        ContentSigner signerBuilder = new JcaContentSignerBuilder("SM3withSM2")
            .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey);
        return csrBuilder.build(signerBuilder);
    }

    public static AlgorithmIdentifier findSignatureAlgorithmIdentifier(String algoName) {
        DefaultSignatureAlgorithmIdentifierFinder sigFinder = new DefaultSignatureAlgorithmIdentifierFinder();
        return sigFinder.find(algoName);
    }

    public static AlgorithmIdentifier findDigestAlgorithmIdentifier(String algoName) {
        DefaultDigestAlgorithmIdentifierFinder digFinder = new DefaultDigestAlgorithmIdentifierFinder();
        return digFinder.find(findSignatureAlgorithmIdentifier(algoName));
    }
}
