package eks

import (
	"context"
	"fmt"
	"time"

	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/applier"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/deploy"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/k8s"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/namer"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/util"
	eksv1beta1 "github.com/upbound/provider-aws/apis/eks/v1beta1"
	iamv1beta1 "github.com/upbound/provider-aws/apis/iam/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

// OIDC task create an oidc provider in aws to auth
type OIDC struct {
	*task.BaseTask
}

func NewOIDC(ctx *task.Context) *OIDC {
	return &OIDC{
		BaseTask: &task.BaseTask{Context: ctx},
	}
}

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

// this oidcprovider resource cannot be migrated from infra-apiserver,
// so let it run for migrated eks.
func (t *OIDC) Create(ctx context.Context) deploy.Result {
	t.BeginAt = util.Pointer(time.Now())
	eks := eksv1beta1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name: t.APPBox.Status.KubernetesClusterName,
		},
	}
	if err := t.Local.Get(ctx, client.ObjectKeyFromObject(&eks), &eks); err != nil {
		return deploy.Panic(err)
	}
	if len(eks.Status.AtProvider.Identity) == 0 || len(eks.Status.AtProvider.Identity[0].Oidc) == 0 ||
		eks.Status.AtProvider.Identity[0].Oidc[0].Issuer == nil {
		return deploy.Panic(fmt.Errorf("wait for eks ready to get oidc issuer"))
	}
	oidc := &iamv1beta1.OpenIDConnectProvider{
		ObjectMeta: metav1.ObjectMeta{
			Name: controllers.UniqueIdentifier(t.APPBox.ObjectMeta, namer.WithPrefix(t.Config.ResourceNamePrefix)),
		},
		Spec: iamv1beta1.OpenIDConnectProviderSpec{
			ForProvider: iamv1beta1.OpenIDConnectProviderParameters{
				ClientIDList: []*string{
					ptr.To("sts.amazonaws.com"),
				},
				ThumbprintList: []*string{
					ptr.To("9e99a48a9960b14926bb7f3b02e22da2b0ab7280"),
				},
				URL: eks.Status.AtProvider.Identity[0].Oidc[0].Issuer,
			},
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{
					Name: t.ProviderConfigName(),
				},
				ManagementPolicies: controllers.GetResourceManagementPolicies(),
			},
		},
	}

	if err := k8s.Apply(ctx, t.Local, oidc); err != nil {
		return deploy.Panic(err)
	}

	return deploy.Done()
}

func (t *OIDC) Delete(ctx context.Context) deploy.Result {
	name := controllers.UniqueIdentifier(t.APPBox.ObjectMeta, namer.WithPrefix(t.Config.ResourceNamePrefix))
	oidc := &iamv1beta1.OpenIDConnectProvider{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
	}
	if err := t.Local.Get(ctx, client.ObjectKeyFromObject(oidc), oidc); client.IgnoreNotFound(err) != nil {
		return deploy.Error(err)
	}
	oidc.Spec.ResourceSpec.ManagementPolicies = xpv1.ManagementPolicies{xpv1.ManagementActionAll}
	if err := k8s.PatchObject(ctx, t.Local, oidc, controllers.ManagementPoliciesPatch); client.IgnoreNotFound(err) != nil {
		return deploy.Error(err)
	}
	if err := k8s.DeleteObject(ctx, t.Local, applier.NewClusterObject[*iamv1beta1.OpenIDConnectProvider](name)); err != nil {
		return deploy.Error(err)
	}

	return deploy.Done()
}
