package common

import (
	"context"
	"fmt"

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

	certv1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"

	"github.com/tidbcloud/eks-provider/controllers/cluster/task"
	"github.com/tidbcloud/infra-provider/pkg/cert"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/k8s"
)

// ComponentsSelfSignedIssuer task will create a ComponentsSelfSignedIssuer
type ComponentsSelfSignedIssuer struct {
	*task.BaseTask
}

func NewComponentsSelfSignedIssuer(ctx *task.Context) *ComponentsSelfSignedIssuer {
	return &ComponentsSelfSignedIssuer{
		BaseTask: &task.BaseTask{Context: ctx},
	}
}

func (t *ComponentsSelfSignedIssuer) Name() string {
	return "ComponentsSelfSignedIssuer"
}

func (t *ComponentsSelfSignedIssuer) Create(ctx context.Context) deploy.Result {
	cli := t.EnvProvider.GetClient()

	caCert := cert.SelfSignedComponentCACertificate(t.Namer.GetTiDBNamespace())
	if err := k8s.Apply(ctx, cli, caCert); err != nil {
		return deploy.Panic(err)
	}

	issuer := cert.TiDBComponentsSelfSignedIssuer(t.Namer.GetTiDBNamespace())
	if err := k8s.Apply(ctx, cli, issuer); err != nil {
		return deploy.Panic(err)
	}
	return deploy.Done()
}

func (t *ComponentsSelfSignedIssuer) PostCreate(ctx context.Context) deploy.Result {
	if err := t.selfSignedClusterIssuerConditionChecker(ctx); err != nil {
		return deploy.Panic(err)
	}
	return deploy.Done()
}

func (t *ComponentsSelfSignedIssuer) selfSignedClusterIssuerConditionChecker(ctx context.Context) error {
	cli := t.EnvProvider.GetClient()

	iss := &certv1.Issuer{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cert.TiDBComponentsSelfSignedIssuerName,
			Namespace: t.Namer.GetTiDBNamespace(),
		},
	}

	if err := cli.Get(ctx, client.ObjectKeyFromObject(iss), iss); err != nil {
		return err
	}
	for _, v := range iss.Status.Conditions {
		if v.Type == certv1.IssuerConditionReady && v.Status == cmmeta.ConditionTrue {
			return nil
		}
	}
	return fmt.Errorf("components self signed issuer %v not ready", cert.TiDBComponentsSelfSignedIssuerName)
}

func (t *ComponentsSelfSignedIssuer) Delete(ctx context.Context) deploy.Result {
	cli := t.EnvProvider.GetClient()
	issuer := cert.TiDBComponentsSelfSignedIssuer(t.Namer.GetTiDBNamespace())
	caCert := cert.SelfSignedComponentCACertificate(t.Namer.GetTiDBNamespace())

	if err := k8s.DeleteObject(ctx, cli, issuer); err != nil {
		return deploy.Error(err)
	}
	if err := k8s.DeleteObject(ctx, cli, caCert); err != nil {
		return deploy.Error(err)
	}
	return deploy.Done()
}
