package commonazure

import (
	"context"
	"fmt"

	"github.com/pingcap/errors"
	aksv1beta1 "github.com/upbound/provider-azure/apis/containerservice/v1beta1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/observability/agent-control-server/pkg/consts"
	"github.com/tidbcloud/observability/agent-control-server/pkg/deploy"
	"github.com/tidbcloud/observability/agent-control-server/pkg/reconciler"
	"github.com/tidbcloud/observability/agent-control-server/pkg/util"
)

type KubeletIdentityTask[T client.Object] struct {
	*reconciler.BaseTask[T]
	cm deploy.ClusterMeta
}

func NewKubeletIdentityTask[T client.Object](ctx *reconciler.Context[T], cm deploy.ClusterMeta) *KubeletIdentityTask[T] {
	return &KubeletIdentityTask[T]{
		BaseTask: &reconciler.BaseTask[T]{Context: ctx},
		cm:       cm,
	}
}

func (t *KubeletIdentityTask[T]) Name() string {
	return "KubeletIdentity"
}

func (t *KubeletIdentityTask[T]) ClusterMeta() deploy.ClusterMeta {
	return t.cm
}

func (t *KubeletIdentityTask[T]) Create(ctx context.Context) deploy.Result {
	// If already fetched, skip.
	if util.GetAnnotation(t.Agent, consts.AnnotationKeyAKSKubeletClientID) != "" &&
		util.GetAnnotation(t.Agent, consts.AnnotationKeyAKSKubeletObjectID) != "" {
		return deploy.Done()
	}

	clusterName := t.cm.K8sClusterName
	if clusterName == "" {
		return deploy.Panic(fmt.Errorf("kubernetes cluster name is empty"))
	}

	aks := &aksv1beta1.KubernetesCluster{}
	if err := t.Local.Get(ctx, client.ObjectKey{Name: clusterName}, aks); err != nil {
		return deploy.Panic(errors.Annotate(err, "failed to get KubernetesCluster"))
	}

	if len(aks.Status.AtProvider.KubeletIdentity) == 0 ||
		aks.Status.AtProvider.KubeletIdentity[0].ClientID == nil ||
		aks.Status.AtProvider.KubeletIdentity[0].ObjectID == nil {
		return deploy.Panic(errors.New("kubeletIdentity not available yet, waiting for AKS cluster to be ready"))
	}

	clientID := *aks.Status.AtProvider.KubeletIdentity[0].ClientID
	objectID := *aks.Status.AtProvider.KubeletIdentity[0].ObjectID
	util.SetAnnotation(t.Agent, consts.AnnotationKeyAKSKubeletClientID, clientID)
	util.SetAnnotation(t.Agent, consts.AnnotationKeyAKSKubeletObjectID, objectID)
	t.L.Info("fetched AKS kubeletIdentity", "clientId", clientID, "objectId", objectID)
	return deploy.Done()
}

func (t *KubeletIdentityTask[T]) Delete(ctx context.Context) deploy.Result {
	return deploy.Done()
}
