package private_ca

import (
	"ALLinSSL/backend/public"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"fmt"
	"math/big"
	"time"

	"github.com/tjfoc/gmsm/sm2"
	gmx509 "github.com/tjfoc/gmsm/x509"
)

func GetSqlite() (*public.Sqlite, error) {
	s, err := public.NewSqlite("data/private_ca.db", "")
	if err != nil {
		return nil, err
	}
	s.TableName = "ca"
	return s, nil
}

// ----------- 标准算法 Root CA -----------
func GenerateRootCAStandard(name, commonName, organization, organizationalUnit, country, province, locality string, keyType KeyType, keyBits, validDays int) (*CAConfig, error) {
	if keyType == KeySM2 {
		return nil, errors.New("use GenerateRootCASM2 for SM2")
	}

	priv, err := generatePrivateKey(keyType, keyBits)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	expire := now.AddDate(0, 0, validDays)
	if validDays <= 0 {
		expire = now.AddDate(10, 0, 0)
	}
	subject := pkix.Name{
		// 通用名称
		CommonName: commonName,
		// 国家代码
		Country: []string{country},
	}
	if organization != "" {
		subject.Organization = []string{organization}
	}
	if organizationalUnit != "" {
		subject.OrganizationalUnit = []string{organizationalUnit}
	}
	if province != "" {
		subject.Province = []string{province}
	}
	if locality != "" {
		subject.Locality = []string{locality}
	}

	tmpl := &x509.Certificate{
		SerialNumber:          big.NewInt(now.UnixNano()),
		Subject:               subject,
		NotBefore:             now,
		NotAfter:              expire,
		IsCA:                  true,
		KeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
		BasicConstraintsValid: true,
		MaxPathLen:            2,
	}

	cert, err := signCert(tmpl, tmpl, priv, priv, keyType)
	if err != nil {
		return nil, err
	}

	cert.KeyType = keyType
	return &CAConfig{
		Name:       name,
		CN:         commonName,
		O:          organization,
		C:          country,
		Cert:       string(cert.CertPEM),
		Key:        string(cert.KeyPEM),
		Algorithm:  string(keyType),
		KeyLength:  int64(keyBits),
		NotBefore:  now.Format("2006-01-02 15:04:05"),
		NotAfter:   expire.Format("2006-01-02 15:04:05"),
		CreateTime: now.Format("2006-01-02 15:04:05"),
	}, nil
}

// ----------- SM2 Root CA (双证书体系) -----------
func GenerateRootCASM2(name, commonName, organization, organizationalUnit, country, province, locality string, validDays int) (*CAConfig, error) {
	// 1. 为签名和加密功能分别生成私钥
	signPriv, err := generatePrivateKey(KeySM2, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to generate SM2 root signing key: %w", err)
	}
	encryptPriv, err := generatePrivateKey(KeySM2, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to generate SM2 root encryption key: %w", err)
	}

	now := time.Now()
	expire := now.AddDate(0, 0, validDays)
	if validDays <= 0 {
		expire = now.AddDate(10, 0, 0)
	}

	subject := pkix.Name{
		// 通用名称
		CommonName: commonName,
		// 国家代码
		Country: []string{country},
	}
	if organization != "" {
		subject.Organization = []string{organization}
	}
	if organizationalUnit != "" {
		subject.OrganizationalUnit = []string{organizationalUnit}
	}
	if province != "" {
		subject.Province = []string{province}
	}
	if locality != "" {
		subject.Locality = []string{locality}
	}

	// 2. 创建根签名证书模板
	signTmpl := &gmx509.Certificate{
		SerialNumber:          big.NewInt(now.UnixNano()),
		Subject:               subject,
		NotBefore:             now,
		NotAfter:              expire,
		IsCA:                  true,
		KeyUsage:              gmx509.KeyUsageCertSign | gmx509.KeyUsageCRLSign,
		BasicConstraintsValid: true,
		MaxPathLen:            2,
	}

	// 3. 创建根加密证书模板
	encryptTmpl := &gmx509.Certificate{
		SerialNumber:          big.NewInt(now.UnixNano() + 1),
		Subject:               subject,
		NotBefore:             now,
		NotAfter:              expire,
		IsCA:                  true,
		KeyUsage:              gmx509.KeyUsageKeyEncipherment | gmx509.KeyUsageDataEncipherment,
		BasicConstraintsValid: true,
		MaxPathLen:            2,
	}

	// 4. 自签名根签名证书 (使用自己的签名私钥)
	signCert, err := signSM2Cert(signTmpl, signTmpl, signPriv.(*sm2.PrivateKey), signPriv.(*sm2.PrivateKey))
	if err != nil {
		return nil, fmt.Errorf("failed to self-sign SM2 root signing cert: %w", err)
	}

	// 5. 使用根签名证书签发根加密证书
	encryptCert, err := signSM2Cert(encryptTmpl, signTmpl, encryptPriv.(*sm2.PrivateKey), signPriv.(*sm2.PrivateKey))
	if err != nil {
		return nil, fmt.Errorf("failed to sign SM2 root encryption cert: %w", err)
	}

	// 6. 组装返回结果
	return &CAConfig{
		Name:       name,
		CN:         commonName,
		O:          organization,
		C:          country,
		Cert:       string(signCert.CertPEM),
		Key:        string(signCert.KeyPEM),
		EnCert:     string(encryptCert.CertPEM),
		EnKey:      string(encryptCert.KeyPEM),
		Algorithm:  "sm2",
		KeyLength:  256,
		NotBefore:  now.Format("2006-01-02 15:04:05"),
		NotAfter:   expire.Format("2006-01-02 15:04:05"),
		CreateTime: now.Format("2006-01-02 15:04:05"),
	}, nil
}

// ----------- 标准算法 Intermediate CA -----------
func GenerateIntermediateCAStandard(name, commonName, organization, organizationalUnit, country, province, locality, cert, key, algorithm string, keyBits, validDays int) (*CAConfig, error) {

	keyType := KeyType(algorithm)
	issuer, err := NewCertificateFromPEMStandard([]byte(cert), []byte(key), keyType)
	if err != nil {
		return nil, fmt.Errorf("failed to parse issuer certificate: %w", err)
	}

	if issuer == nil {
		return nil, errors.New("issuer is nil")
	}
	if issuer.KeyType != keyType {
		return nil, fmt.Errorf("issuer and intermediate key type mismatch: %s != %s", issuer.KeyType, keyType)
	}
	if keyType == KeySM2 {
		return nil, errors.New("use GenerateIntermediateCASM2 for SM2")
	}

	priv, err := generatePrivateKey(keyType, keyBits)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	expire := now.AddDate(0, 0, validDays)
	if validDays <= 0 {
		expire = now.AddDate(5, 0, 0)
	}

	subject := pkix.Name{
		// 通用名称
		CommonName: commonName,
		// 国家代码
		Country: []string{country},
	}
	if organization != "" {
		subject.Organization = []string{organization}
	}
	if organizationalUnit != "" {
		subject.OrganizationalUnit = []string{organizationalUnit}
	}
	if province != "" {
		subject.Province = []string{province}
	}
	if locality != "" {
		subject.Locality = []string{locality}
	}

	tmpl := &x509.Certificate{
		SerialNumber:          big.NewInt(now.UnixNano()),
		Subject:               subject,
		NotBefore:             now,
		NotAfter:              expire,
		IsCA:                  true,
		KeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
		BasicConstraintsValid: true,
		MaxPathLen:            1,
	}

	certObj, err := signCert(tmpl, issuer.Cert, priv, issuer.Key, keyType)
	if err != nil {
		return nil, err
	}

	certObj.KeyType = keyType
	return &CAConfig{
		Name:       name,
		CN:         commonName,
		O:          organization,
		C:          country,
		Cert:       string(certObj.CertPEM),
		Key:        string(certObj.KeyPEM),
		Algorithm:  string(keyType),
		KeyLength:  int64(keyBits),
		NotBefore:  now.Format("2006-01-02 15:04:05"),
		NotAfter:   expire.Format("2006-01-02 15:04:05"),
		CreateTime: now.Format("2006-01-02 15:04:05"),
	}, nil
}

// ----------- SM2 Intermediate CA (双证书体系) -----------
func GenerateIntermediateCASM2(name, commonName, organization, organizationalUnit, country, province, locality, cert, key, enCert, enKey string, validDays int) (*CAConfig, error) {

	issuer, err := NewCertificateFromPEMSM2([]byte(cert), []byte(key), []byte(enCert), []byte(enKey))
	if err != nil {
		return nil, fmt.Errorf("failed to parse issuer certificate: %w", err)
	}
	if issuer == nil {
		return nil, errors.New("issuer is nil")
	}
	if issuer.KeyType != KeySM2 || issuer.SignGmCert == nil {
		return nil, errors.New("issuer must be a valid SM2 dual-certificate CA")
	}

	// 1. 为签名和加密功能分别生成私钥
	signPriv, err := generatePrivateKey(KeySM2, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to generate SM2 intermediate signing key: %w", err)
	}
	encryptPriv, err := generatePrivateKey(KeySM2, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to generate SM2 intermediate encryption key: %w", err)
	}

	now := time.Now()
	expire := now.AddDate(0, 0, validDays)
	if validDays <= 0 {
		expire = now.AddDate(5, 0, 0)
	}

	subject := pkix.Name{
		// 通用名称
		CommonName: commonName,
		// 国家代码
		Country: []string{country},
	}
	if organization != "" {
		subject.Organization = []string{organization}
	}
	if organizationalUnit != "" {
		subject.OrganizationalUnit = []string{organizationalUnit}
	}
	if province != "" {
		subject.Province = []string{province}
	}
	if locality != "" {
		subject.Locality = []string{locality}
	}

	// 2. 创建中间签名证书模板
	signTmpl := &gmx509.Certificate{
		SerialNumber:          big.NewInt(now.UnixNano()),
		Subject:               subject,
		NotBefore:             now,
		NotAfter:              expire,
		IsCA:                  true,
		KeyUsage:              gmx509.KeyUsageCertSign | gmx509.KeyUsageCRLSign,
		BasicConstraintsValid: true,
		MaxPathLen:            1,
	}

	// 3. 创建中间加密证书模板
	encryptTmpl := &gmx509.Certificate{
		SerialNumber:          big.NewInt(now.UnixNano() + 1),
		Subject:               subject,
		NotBefore:             now,
		NotAfter:              expire,
		IsCA:                  true,
		KeyUsage:              gmx509.KeyUsageKeyEncipherment | gmx509.KeyUsageDataEncipherment,
		BasicConstraintsValid: true,
		MaxPathLen:            1,
	}

	// 4. 使用颁发者的签名证书和私钥，签发中间签名证书
	signCert, err := signSM2Cert(signTmpl, issuer.SignGmCert, signPriv.(*sm2.PrivateKey), issuer.Key.(*sm2.PrivateKey))
	if err != nil {
		return nil, fmt.Errorf("failed to sign SM2 intermediate signing cert: %w", err)
	}

	// 5. 使用颁发者的签名证书和私钥，签发中间加密证书
	encryptCert, err := signSM2Cert(encryptTmpl, issuer.SignGmCert, encryptPriv.(*sm2.PrivateKey), issuer.Key.(*sm2.PrivateKey))
	if err != nil {
		return nil, fmt.Errorf("failed to sign SM2 intermediate encryption cert: %w", err)
	}

	// 6. 组装返回结果
	return &CAConfig{
		Name:       name,
		CN:         commonName,
		O:          organization,
		C:          country,
		Cert:       string(signCert.CertPEM),
		Key:        string(signCert.KeyPEM),
		EnCert:     string(encryptCert.CertPEM),
		EnKey:      string(encryptCert.KeyPEM),
		Algorithm:  "sm2",
		KeyLength:  256,
		NotBefore:  now.Format("2006-01-02 15:04:05"),
		NotAfter:   expire.Format("2006-01-02 15:04:05"),
		CreateTime: now.Format("2006-01-02 15:04:05"),
	}, nil
}

// NewCertificateFromPEMStandard 从PEM格式的标准算法证书和私钥创建Certificate对象
func NewCertificateFromPEMStandard(certPEM, keyPEM []byte, keyType KeyType) (*Certificate, error) {
	if keyType == KeySM2 {
		return nil, errors.New("use NewCertificateFromPEMSM2 for SM2 certificates")
	}

	certBlock, _ := pem.Decode(certPEM)
	if certBlock == nil || certBlock.Type != "CERTIFICATE" {
		return nil, errors.New("failed to decode certificate PEM")
	}

	keyBlock, _ := pem.Decode(keyPEM)
	if keyBlock == nil {
		return nil, errors.New("failed to decode key PEM")
	}

	cert := &Certificate{
		CertPEM: certPEM,
		KeyPEM:  keyPEM,
		KeyType: keyType,
	}

	var err error
	cert.Cert, err = x509.ParseCertificate(certBlock.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse standard certificate: %w", err)
	}

	switch keyType {
	case KeyRSA:
		cert.Key, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
		if err != nil {
			pkcs8Key, err2 := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
			if err2 != nil {
				return nil, fmt.Errorf("failed to parse rsa private key (PKCS1 and PKCS8): %w", err)
			}
			cert.Key = pkcs8Key
			err = nil
		}
	case KeyECDSA:
		cert.Key, err = x509.ParseECPrivateKey(keyBlock.Bytes)
		if err != nil {
			pkcs8Key, err2 := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
			if err2 != nil {
				return nil, fmt.Errorf("failed to parse ecdsa private key (EC and PKCS8): %w", err)
			}
			cert.Key = pkcs8Key
			err = nil
		}
	default:
		return nil, fmt.Errorf("unsupported key type: %s", keyType)
	}

	return cert, nil
}

// NewCertificateFromPEMSM2 从PEM格式的国密双证书和双私钥创建Certificate对象
func NewCertificateFromPEMSM2(signCertPEM, signKeyPEM, encryptCertPEM, encryptKeyPEM []byte) (*Certificate, error) {
	// 解析签名证书
	signCertBlock, _ := pem.Decode(signCertPEM)
	if signCertBlock == nil || signCertBlock.Type != "CERTIFICATE" {
		return nil, errors.New("failed to decode signing certificate PEM")
	}
	signGmCert, err := gmx509.ParseCertificate(signCertBlock.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse sm2 signing certificate: %w", err)
	}

	// 解析签名私钥
	signKeyBlock, _ := pem.Decode(signKeyPEM)
	if signKeyBlock == nil {
		return nil, errors.New("failed to decode signing key PEM")
	}
	signKey, err := gmx509.ParsePKCS8PrivateKey(signKeyBlock.Bytes, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to parse sm2 signing private key: %w", err)
	}

	// 解析加密证书
	encryptCertBlock, _ := pem.Decode(encryptCertPEM)
	if encryptCertBlock == nil || encryptCertBlock.Type != "CERTIFICATE" {
		return nil, errors.New("failed to decode encryption certificate PEM")
	}
	encryptGmCert, err := gmx509.ParseCertificate(encryptCertBlock.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse sm2 encryption certificate: %w", err)
	}

	// 解析加密私钥
	encryptKeyBlock, _ := pem.Decode(encryptKeyPEM)
	if encryptKeyBlock == nil {
		return nil, errors.New("failed to decode encryption key PEM")
	}
	encryptKey, err := gmx509.ParsePKCS8PrivateKey(encryptKeyBlock.Bytes, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to parse sm2 encryption private key: %w", err)
	}

	return &Certificate{
		SignCertPEM:    signCertPEM,
		SignKeyPEM:     signKeyPEM,
		EncryptCertPEM: encryptCertPEM,
		EncryptKeyPEM:  encryptKeyPEM,
		Key:            signKey,
		EncryptKey:     encryptKey,
		SignGmCert:     signGmCert,
		EncryptGmCert:  encryptGmCert,
		KeyType:        KeySM2,
	}, nil
}
