package task

import (
	"context"
	"fmt"
	"strconv"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	agentv2 "github.com/tidbcloud/observability/agent-control-server/api/v2"
	"github.com/tidbcloud/observability/agent-control-server/controllers/kubernetesagent/metadata"
	"github.com/tidbcloud/observability/agent-control-server/pkg/agentbuild"
	"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 VectorTask struct {
	*reconciler.BaseTask[*agentv2.KubernetesAgent]
}

func NewVectorTask(ctx *reconciler.Context[*agentv2.KubernetesAgent]) *VectorTask {
	return &VectorTask{
		BaseTask: &reconciler.BaseTask[*agentv2.KubernetesAgent]{Context: ctx},
	}
}

func (t *VectorTask) Name() string {
	return "Vector"
}

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

func (t *VectorTask) Create(ctx context.Context) deploy.Result {
	cfg := t.Config.O11yConfig.CustomerConfigsV2.NextGen.K8s.BuildConfig().Vector
	return deploy.PanicOrDone(agentbuild.InstallOrUpgradeHelm(
		ctx,
		t.Remote,
		t.build,
		cfg.Chart.Name,
		cfg.Chart.Version,
		consts.O11yNameVector,
		t.buildNamespace(),
		nil,
	))
}

func (t *VectorTask) PostCreate(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	return deploy.PanicOrDone(agentbuild.CheckDaemonSetReady(ctx, cli, consts.O11yNameVector, t.buildNamespace()))
}

func (t *VectorTask) Delete(ctx context.Context) deploy.Result {
	return deploy.PanicOrDone(agentbuild.DeleteHelm(ctx, t.Remote, consts.O11yNameVector, t.buildNamespace()))
}

func (t *VectorTask) PostDelete(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	return deploy.PanicOrDone(agentbuild.CheckDaemonSetDeleted(ctx, cli, consts.O11yNameVector, t.buildNamespace()))
}

func (t *VectorTask) build() (string, error) {
	// TODO: temporary use ak/sk on alicloud
	// When vector supports node role for oss, remove this
	var accessKey, secretKey string
	if t.Config.O11yConfig.Vendor == "alicloud" {
		secret := &corev1.Secret{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "o11y-oss-secret",
				Namespace: "observability",
			},
		}
		if err := t.Local.Get(context.Background(), client.ObjectKeyFromObject(secret), secret); err != nil {
			return "", err
		}
		accessKey = string(secret.Data["access_key"])
		secretKey = string(secret.Data["secret_key"])
	}

	cfg := t.Config.O11yConfig.CustomerConfigsV2.NextGen.K8s.BuildConfig().Vector
	imageRepo, imageTag, err := agentbuild.BuildVectorImage(t.Agent, cfg.Image)
	if err != nil {
		return "", err
	}
	resourcesJson, err := agentbuild.BuildVectorResources(t.Agent, cfg.Resources.DeepCopy())
	if err != nil {
		return "", err
	}

	configTemplate := fmt.Sprintf("k8s/vector-values-%s.yaml", t.Config.O11yConfig.Vendor)
	tmpl, err := agentbuild.BuildVectorTemplate(t.Agent, t.Templates, configTemplate)
	if err != nil {
		return "", err
	}

	initContainerImage := cfg.InitContainerImage
	if initContainerImage == "" {
		initContainerImage = "busybox"
	}
	podHostNetwork := ""
	if cfg.PodHostNetwork != nil {
		podHostNetwork = strconv.FormatBool(*cfg.PodHostNetwork)
	}
	// Keep network settings in the template input so BuildVectorValues renders the final YAML once.
	return agentbuild.BuildVectorValues(tmpl, map[string]string{
		"ImageRepo":          imageRepo,
		"ImageTag":           imageTag,
		"InitContainerImage": initContainerImage,
		"PodHostNetwork":     podHostNetwork,
		"DNSPolicy":          cfg.DNSPolicy,
		"Resources":          resourcesJson,
		"Region":             t.Config.O11yConfig.Region,
		"Bucket":             util.GetAnnotation(t.Agent, consts.AnnotationKeyO11yLogBucketName),
		"RoleARN":            util.GetAnnotation(t.Agent, consts.AnnotationKeyO11yAgentRoleArn),
		"AccessKeyID":        accessKey,
		"SecretAccessKey":    secretKey,
		"LokiURL":            fmt.Sprintf("http://%s/loki", util.GetAnnotation(t.Agent, consts.AnnotationKeyO11yServiceDNSName)),
		"OpenSearchURL":      util.GetAnnotation(t.Agent, consts.AnnotationKeyO11yOpenSearchURL),
		"ClusterEnv":         t.Config.O11yConfig.Env,
		"ClusterName":        t.Agent.Spec.KubernetesClusterName,
		"PriorityClassName":  consts.PriorityClassNameNodeCritical,
		"TenantID":           t.Agent.Spec.O11y.TenantID,
		"ProjectID":          util.GetLabel(t.Agent, consts.LabelKeyO11yProjectID),
		"AzureClientID":      util.GetAnnotation(t.Agent, consts.AnnotationKeyAKSKubeletClientID),
		"ContainerName":      util.GetAnnotation(t.Agent, consts.AnnotationKeyO11yLogBucketName),
		"StorageAccount":     util.GetAnnotation(t.Agent, consts.AnnotationKeyO11yLogStorageAccount),
	})
}

func (t *VectorTask) buildNamespace() string {
	if t.Config.IsServerlessMode() {
		return consts.ServerlessObservabilityNamespace
	}
	return consts.O11ySystemNamespace
}
