package cn.anicert.secure.access.crypto.util;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;

import java.io.ByteArrayInputStream;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Enumeration;
import java.util.StringTokenizer;

/**
 * @company cn.anicert
 * @author: wangpengyuan
 * @create: 2024-03-07
 * @description 证书工具类
 **/
public class CertUtils extends BaseCryptoUtil {

    public static Certificate parseSM2Certificate(String cert) throws Exception {
        byte[] certBytes = Base64.decode(cert);
        return parseSM2Certificate(certBytes);
    }

    public static Certificate parseSM2Certificate(byte[] certBytes) throws Exception {
        ByteArrayInputStream is = new ByteArrayInputStream(certBytes);
        ASN1InputStream asn1InputStream = new ASN1InputStream(is);
        ASN1Primitive asn1Primitive = asn1InputStream.readObject();
        return Certificate.getInstance(asn1Primitive);
    }

    public static String getCertInfo(Certificate cert, long infoType) {
        String info = null;
        try {
            X500Name subjectX509Name = cert.getSubject();
            String subjectName = subjectX509Name.toString().trim();

            X500Name issuerX509Name = cert.getIssuer();
            String issuerName = issuerX509Name.toString().trim();

            // 用户国家名
            String striC = null;
            // 用户组织名
            String striO = null;
            // 用户部门名
            String striOU = null;
            // 用户省州名
            String striS = null;
            // 用户通用名
            String striCN = null;
            // 用户城市名
            String striL = null;
            // 用户EMAIL地址
            String striE = null;

            StringTokenizer stSubjectDN = new StringTokenizer(subjectName, ",");
            while (stSubjectDN.hasMoreTokens()) {
                String strSubj = stSubjectDN.nextToken().trim();
                if (strSubj.contains("C=")) {
                    striC = strSubj.substring(strSubj.indexOf("C=") + 2);
                } else if (strSubj.contains("O=")) {
                    striO = strSubj.substring(strSubj.indexOf("O=") + 2);
                } else if (strSubj.contains("OU=")) {
                    striOU = strSubj.substring(strSubj.indexOf("OU=") + 3);
                } else if (strSubj.contains("CN=")) {
                    striCN = strSubj.substring(strSubj.indexOf("CN=") + 3);
                } else if (strSubj.contains("L=")) {
                    striL = strSubj.substring(strSubj.indexOf("L=") + 2);
                } else if (strSubj.contains("EMAILADDRESS=")) {// E 和 EMAILADDRESS 都是email address的意思，优先取E
                    striE = strSubj.substring(strSubj.indexOf("EMAILADDRESS=") + 13);
                } else if (strSubj.contains("E=")) {
                    striE = strSubj.substring(strSubj.indexOf("E=") + 2);
                } else if (strSubj.contains("ST=")) {
                    striS = strSubj.substring(strSubj.indexOf("ST=") + 3);
                }
            }
            // 用户国家名(备用名)
            String strC = null;
            // 用户组织名(备用名)
            String strO = null;
            // 用户部门名(备用名)
            String strOU = null;
            // 用户省州名(备用名)
            String strS = null;
            // 用户通用名(备用名)
            String strCN = null;
            // 用户城市名(备用名)
            String strL = null;
            // 用户EMAIL地址(备用名)
            String strE = null;

            Extensions extensions = cert.getTBSCertificate().getExtensions();
            int itype = (int) infoType;
            String infostr = null;
            switch (itype) {
                case 1:
                    info = String.valueOf(cert.getVersion());// TODO test
                    break;
                case 2:
                    info = Hex.toHexString(cert.getSerialNumber().getValue().toByteArray());// TODO
                    break;
                case 3:
                    info = cert.getSignatureAlgorithm().getAlgorithm().getId();// TODO
                    break;
                case 8:
                    infostr = issuerName;
                    StringTokenizer stIssuerDN = new StringTokenizer(infostr, ",");
                    while (stIssuerDN.hasMoreTokens()) {
                        String strIss = stIssuerDN.nextToken().trim();
                        if (strIss.indexOf("CN=") == 0) {
                            info = strIss.substring(3);
                        }
                    }
                    break;
                case 11:
                    break;
                case 12:
                    break;
                case 13:
                    info = striC;
                    break;
                case 14:
                    info = striO;
                    break;
                case 15:
                    info = striOU;
                    break;
                case 16:
                    info = striS;
                    break;
                case 17:
                    info = striCN;
                    break;
                case 18:
                    info = striL;
                    break;
                case 19:
                    info = striE;
                    break;
                case 20:
                    info = issuerName;
                    break;
                case 21:
                    info = subjectName;
                    break;
                case 22:
                    info = null;
                    break;
                case 23:
                    info = strC;
                    break;
                case 24:
                    info = strO;
                    break;
                case 25:
                    info = strOU;
                    break;
                case 26:
                    info = strS;
                    break;
                case 27:
                    info = strCN;
                    break;
                case 28:
                    info = strL;
                    break;
                case 29:
                    info = strE;
                    break;
                case 30:
                    SubjectPublicKeyInfo spki = cert.getSubjectPublicKeyInfo();
                    byte[] bPubKey = spki.getPublicKeyData().getBytes();
                    info = Base64.toBase64String(bPubKey);
                    break;
                case 31:
                    break;
                case 32:
                    Instant newEndDate = cert.getEndDate().getDate().toInstant();
                    LocalDateTime newEndTime = LocalDateTime.ofInstant(newEndDate, ZoneId.systemDefault());
                    info = DateTimeFormatter.ofPattern("yyyy/MM/dd/HH/mm/ss").format(newEndTime);
                    break;
                default:
                    info = null;
                    break;
            }
        } catch (Exception e) {
            info = null;
            throw new RuntimeException(e);
        }
        return info;
    }

    public static String getSubjectDn(String signature) throws Exception {
        try {
            ContentInfo info = ContentInfo.getInstance(ASN1Util.checkAndGetASN1Object(Base64.decode(signature)));
            SignedData sData = SignedData.getInstance(info.getContent());
            Enumeration certEnum = sData.getCertificates().getObjects();
            ASN1Sequence certSeq = (ASN1Sequence) certEnum.nextElement();
            Certificate signCert = Certificate.getInstance(certSeq);
            String subjectTemp = signCert.getSubject().toString();
            String[] subjectArray = subjectTemp.split(",");
            String subjectCN = "";
            for (String subject : subjectArray) {
                if (subject.toUpperCase().contains("CN=")) {
                    subjectCN = subject.substring(subject.toUpperCase().indexOf("CN=") + 3);
                }
            }
            return subjectCN;
        } catch (Exception e) {
            throw new Exception();
        }
    }

//    public static void main(String[] args) throws Exception{
//        String sign = "MIIDogYKKoEcz1UGAQQCAqCCA5IwggOOAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICnjCCApowggI+oAMCAQICEhACBQMjATAQixyTax6fhHhfmTAMBggqgRzPVQGDdQUAMEQxCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhDSE5DVERJRDERMA8GA1UECwwIQ0hOQ1RESUQxDzANBgNVBAMMBllXQ0EwMTAeFw0yMzAxMzAwMjE5MjNaFw0zMzAxMjcwMjE5MjNaMDExDzANBgNVBAMMBlJaRlcwMjERMA8GA1UECwwIQ0hOQ1RESUQxCzAJBgNVBAYTAkNOMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEsHlD650v3WqpL9e4Ttn4tqmnslXLCvnpY2mSWc97oeDzDojKMlTiabGl3RDOMtfOAS0GTLaUOSqJtpsjQ8//8KOCAR8wggEbMA4GA1UdDwEB/wQEAwIGwDAJBgNVHRMEAjAAMBAGCGCGSAGG+EQCBARYWFhYMBIGCiqBHIbvMgIBARcEBFhYWFgwgZcGA1UdHwSBjzCBjDBMoEqgSKRGMEQxDzANBgNVBAMMBllXQ0EwMTERMA8GA1UECwwIQ0hOQ1RESUQxETAPBgNVBAoMCENITkNURElEMQswCQYDVQQGEwJDTjA8oDqgOIY2aHR0cDovLzE3Mi4yOC4zMC44OjE4MDYwL2Nhd2ViL2NybC9ZV0NBMDEvWVdDQTAxXzAuY3JsMB0GA1UdDgQWBBQjW5xU5r7FxfDzwGmuIURdI4wPITAfBgNVHSMEGDAWgBSbWAb0NoA4TNCfLq9OLouWdM2BqDAMBggqgRzPVQGDdQUAA0gAMEUCICYfXqrK3a+Urgs7MpV54ayfHXJwLzpqHnmy3h82oarjAiEAvJtl9XE0Pfp59eiuZcTdsFiWZizZCpRQE75qmDxI+jIxgcgwgcUCAQEwWjBEMQswCQYDVQQGEwJDTjERMA8GA1UECgwIQ0hOQ1RESUQxETAPBgNVBAsMCENITkNURElEMQ8wDQYDVQQDDAZZV0NBMDECEhACBQMjATAQixyTax6fhHhfmTAMBggqgRzPVQGDEQUAMA0GCSqBHM9VAYItAQUABEcwRQIhALey3ijM74mPVSZHxnrr5acW0RX97/EO+D+U4aLPNcpWAiBzSme9krCy4ojVo9QDe+ifq7bSGffbBsC16yAburM7cQ==";
//        System.out.println(getSubjectDn(sign));
//    }
}