package cloud

import (
	"context"

	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/ticdc-service-ng/pkg/consts"
	"github.com/tidbcloud/ticdc-service-ng/pkg/k8s"
)

type selfSignedIssuer struct {
	issuerName string
	commonName string
}

func NewSelfSignedCertificateProvider(issuerName, commonName string) CertificateProvider {
	return &selfSignedIssuer{
		issuerName: issuerName,
		commonName: commonName,
	}
}

func (p *selfSignedIssuer) BuildCertificate(name types.NamespacedName, certReq *CertificateRequest) (client.Object, error) {
	cert := &v1.Certificate{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name.Name,
			Namespace: name.Namespace,
		},
		Spec: v1.CertificateSpec{
			SecretName:  name.Name,
			Duration:    certReq.Duration,
			RenewBefore: certReq.RenewBefore,
			CommonName:  p.commonName,
			Subject: &v1.X509Subject{
				Organizations: []string{consts.CertOrganization},
			},
			Usages: []v1.KeyUsage{
				v1.UsageServerAuth,
				v1.UsageClientAuth,
			},
			DNSNames:    certReq.DNSNames,
			IPAddresses: certReq.IPAddresses,
			IssuerRef: cmmeta.ObjectReference{
				Name:  p.issuerName,
				Kind:  "Issuer",
				Group: "cert-manager.io",
			},
		},
	}
	return cert, nil
}

func (p *selfSignedIssuer) DeleteCertificate(ctx context.Context, cli client.Client, name types.NamespacedName) error {
	cert := v1.Certificate{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name.Name,
			Namespace: name.Namespace,
		},
	}
	return k8s.DeleteObject(ctx, cli, &cert)
}

type pcaIssuer struct {
	issuerName string
	commonName string
}

func NewPCACertificateProvider(issuerName, commonName string) CertificateProvider {
	return &pcaIssuer{
		issuerName: issuerName,
		commonName: commonName,
	}
}

func (p *pcaIssuer) BuildCertificate(name types.NamespacedName, certReq *CertificateRequest) (client.Object, error) {
	cert := &v1.Certificate{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name.Name,
			Namespace: name.Namespace,
		},
		Spec: v1.CertificateSpec{
			SecretName:  name.Name,
			Duration:    certReq.Duration,
			RenewBefore: certReq.RenewBefore,
			CommonName:  p.commonName,
			Subject: &v1.X509Subject{
				Organizations: []string{consts.CertOrganization},
			},
			Usages: []v1.KeyUsage{
				v1.UsageServerAuth,
				v1.UsageClientAuth,
			},
			DNSNames:    certReq.DNSNames,
			IPAddresses: certReq.IPAddresses,
			IssuerRef: cmmeta.ObjectReference{
				Name:  p.issuerName,
				Kind:  "AWSPCAIssuer",
				Group: "awspca.cert-manager.io",
			},
		},
	}
	return cert, nil
}

func (p *pcaIssuer) DeleteCertificate(ctx context.Context, cli client.Client, name types.NamespacedName) error {
	cert := v1.Certificate{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name.Name,
			Namespace: name.Namespace,
		},
	}
	return k8s.DeleteObject(ctx, cli, &cert)
}
