package task

import (
	"context"

	vmoperatorv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	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"
)

const agentControlServerName = "o11y-agent-control-server"

type VMServiceScrapeTask struct {
	*reconciler.BaseTask[*agentv2.KubernetesAgent]
}

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

func (t *VMServiceScrapeTask) Name() string {
	return "VMServiceScrape"
}

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

func (t *VMServiceScrapeTask) Create(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	return deploy.PanicOrDone(agentbuild.CreateOrUpdateVMServiceScrape(ctx, cli, t.build))
}

func (t *VMServiceScrapeTask) PostCreate(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	if err := agentbuild.CheckVMServiceScrapeReady(ctx, cli, agentControlServerName, t.buildNamespace()); err != nil {
		return deploy.Panic(err)
	}
	return deploy.Done()
}

func (t *VMServiceScrapeTask) Delete(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	if err := agentbuild.DeleteVMServiceScrape(ctx, cli, agentControlServerName, t.buildNamespace()); err != nil {
		return deploy.Panic(err)
	}
	return deploy.Done()
}

func (t *VMServiceScrapeTask) PostDelete(ctx context.Context) deploy.Result {
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	if err := agentbuild.CheckVMServiceScrapeDeleted(ctx, cli, agentControlServerName, t.buildNamespace()); err != nil {
		return deploy.Panic(err)
	}
	return deploy.Done()
}

func (t *VMServiceScrapeTask) build() (*vmoperatorv1beta1.VMServiceScrape, error) {
	return &vmoperatorv1beta1.VMServiceScrape{
		ObjectMeta: metav1.ObjectMeta{
			Name:      agentControlServerName,
			Namespace: t.buildNamespace(),
		},
		Spec: vmoperatorv1beta1.VMServiceScrapeSpec{
			Selector: metav1.LabelSelector{
				MatchLabels: map[string]string{"app": agentControlServerName},
			},
			Endpoints: []vmoperatorv1beta1.Endpoint{
				{
					Port: "http",
					EndpointScrapeParams: vmoperatorv1beta1.EndpointScrapeParams{
						Path:   "/metrics",
						Scheme: "http",
					},
				},
			},
		},
	}, nil
}

func (t *VMServiceScrapeTask) buildNamespace() string {
	return consts.ServerlessObservabilityNamespace
}
