package task

import (
	"context"

	agentv2 "github.com/tidbcloud/observability/agent-control-server/api/v2"
	"github.com/tidbcloud/observability/agent-control-server/controllers/o11ytidbagent/metadata"
	"github.com/tidbcloud/observability/agent-control-server/pkg/commontasks"
	"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/o11y"
	"github.com/tidbcloud/observability/agent-control-server/pkg/reconciler"
	"github.com/tidbcloud/observability/agent-control-server/pkg/util"
)

const (
	alertTempID    = "95072d4e-5676-4084-bdf1-09aca85881f2"
	alertTempIDDev = "95072d4e-5676-4084-bdf1-09aca85881f2-dev"
)

type BackendTask struct {
	*reconciler.BaseTask[*agentv2.O11yTiDBAgent]
	Inner *commontasks.BackendTask
}

func NewBackendTask(ctx *reconciler.Context[*agentv2.O11yTiDBAgent]) *BackendTask {
	inner := &commontasks.BackendTask{
		L:       ctx.L,
		Agent:   ctx.Agent,
		O11yAPI: &ctx.O11yAPI,
	}
	// For GCP and Azure, we need to pass agentAccessARN and agentManagerARN during delete
	switch ctx.Config.O11yConfig.Vendor {
	case consts.VendorTypeGCP:
		inner.WithAgentAccessARN = true
		inner.AgentAccessARNKey = consts.AnnotationKeyO11yNodeSA
		if ctx.Agent.Spec.GKE != nil {
			inner.AgentManagerARNFunc = func() string { return ctx.Agent.Spec.GKE.Project }
		}
	case consts.VendorTypeAzure:
		inner.AgentAccessARNKey = consts.AnnotationKeyAKSKubeletObjectID
		if ctx.Agent.Spec.AKS != nil {
			inner.AgentManagerARNFunc = func() string { return ctx.Agent.Spec.AKS.SubscriptionID }
		}
	}
	return &BackendTask{
		BaseTask: &reconciler.BaseTask[*agentv2.O11yTiDBAgent]{Context: ctx},
		Inner:    inner,
	}
}

func (t *BackendTask) Name() string {
	return "Backend"
}

func (t *BackendTask) ClusterMeta() deploy.ClusterMeta {
	return metadata.ClusterMeta(t.Agent)
}

func (t *BackendTask) Create(ctx context.Context) deploy.Result {
	alertID := alertTempID
	if t.Config.O11yConfig.Env != "prod" {
		alertID = alertTempIDDev
	}
	accountID := ""
	if t.Agent.Spec.EKS != nil {
		accountID = t.Agent.Spec.EKS.AccountID
	}
	params := o11y.CreateParamsV3(ctx,
		t.Config.O11yConfig.Vendor,
		t.Config.O11yConfig.LogicRegion,
		t.Agent.Spec.O11y.BizType,
		t.Agent.Spec.O11y.TenantID,
		t.Agent.Spec.O11y.ProjectID,
		t.Agent.Spec.O11y.ApplicationID,
		accountID,
		alertID,
	)
	// For GCP: agentAccessAccount is empty, create only passes projectID as agentManagerARN.
	// For Azure: agentAccessAccount is empty, agentAccessARN is kubelet object ID, agentManagerARN is subscriptionID
	switch t.Config.O11yConfig.Vendor {
	case consts.VendorTypeGCP:
		if t.Agent.Spec.GKE != nil {
			params = params.WithAgentManagerARN(t.Agent.Spec.GKE.Project)
		}
	case consts.VendorTypeAzure:
		if t.Agent.Spec.AKS != nil {
			params = params.WithAgentAccessARN(util.GetAnnotation(t.Agent, consts.AnnotationKeyAKSKubeletObjectID)).
				WithAgentManagerARN(t.Agent.Spec.AKS.SubscriptionID).
				WithSkipEndpointServiceName(true)
		}
	}
	return t.Inner.Create(ctx, params, t.Agent.Spec.Pause, false)
}

func (t *BackendTask) PostCreate(ctx context.Context) deploy.Result {
	return t.Inner.PostCreate(ctx, t.Agent.Spec.Pause)
}

func (t *BackendTask) Delete(ctx context.Context) deploy.Result {
	return t.Inner.Delete(ctx,
		t.Config.O11yConfig.Vendor,
		t.Config.O11yConfig.LogicRegion,
		t.Agent.Spec.O11y.TenantID,
		t.Agent.Spec.O11y.ProjectID,
		t.Agent.Spec.O11y.ApplicationID,
		t.Agent.Spec.O11y.BizType,
	)
}
