package task

import (
	"context"
	"fmt"

	yaml "sigs.k8s.io/yaml/goyaml.v3"

	agentv2 "github.com/tidbcloud/observability/agent-control-server/api/v2"
	"github.com/tidbcloud/observability/agent-control-server/controllers/o11yk8sagent/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/helmcli"
	"github.com/tidbcloud/observability/agent-control-server/pkg/reconciler"
)

type OperatorTask struct {
	*reconciler.BaseTask[*agentv2.O11yK8sAgent]
}

func NewOperatorTask(ctx *reconciler.Context[*agentv2.O11yK8sAgent]) *OperatorTask {
	return &OperatorTask{
		BaseTask: &reconciler.BaseTask[*agentv2.O11yK8sAgent]{Context: ctx},
	}
}

func (t *OperatorTask) Name() string {
	return "Operator"
}

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

func (t *OperatorTask) Create(ctx context.Context) deploy.Result {
	helm, err := helmcli.BuildHelmClient(ctx, t.Remote, consts.O11ySystemNamespace)
	if err != nil {
		return deploy.Panic(err)
	}
	for name, chart := range t.Config.O11yConfig.CustomerConfigsV2.Dedicated.Charts {
		// Inject default tolerations so the operator pod can be scheduled onto
		// the o11y-dedicated tainted node pool.
		values := agentbuild.MergeOperatorChartValues(chart.Values, t.Agent.Spec.O11y.ProjectID)
		valuesYaml, err := yaml.Marshal(values)
		if err != nil {
			return deploy.Panic(fmt.Errorf("failed to marshal values: %w", err))
		}
		if err := helmcli.InstallOrUpgradeChart(
			ctx,
			helm,
			name,
			chart.Name,
			consts.O11ySystemNamespace,
			chart.Version,
			string(valuesYaml),
			nil,
		); err != nil {
			return deploy.Panic(err)
		}
	}
	return deploy.Done()
}

func (t *OperatorTask) PostCreate(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	for name := range t.Config.O11yConfig.CustomerConfigsV2.Dedicated.Charts {
		if err := agentbuild.CheckDeploymentReady(ctx, cli, name, consts.O11ySystemNamespace); err != nil {
			return deploy.Panic(err)
		}
	}
	return deploy.Done()
}
