package common

import (
	"context"
	"fmt"

	"helm.sh/helm/v3/pkg/chart"
	"helm.sh/helm/v3/pkg/chart/loader"
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"

	"github.com/tidbcloud/eks-provider/controllers/network/task"
	"github.com/tidbcloud/infra-provider/pkg/config"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/helm"
)

const tiflowOperatorNamespace = "tidb-admin"

type tiflowOperatorConfig struct {
	helmChartPath string
	crdPaths      []string
	image         config.ImageConfig
}

func (c *tiflowOperatorConfig) GetNamespace() string {
	return tiflowOperatorNamespace
}

func (c *tiflowOperatorConfig) GetName() string {
	return "tiflow-operator"
}

func (c *tiflowOperatorConfig) ToHelmValues() map[string]interface{} {
	res := map[string]interface{}{
		"replicaCount": 1,
		"image": map[string]string{
			"repository": c.image.Repo,
			"tag":        c.image.Tag,
		},
	}
	return res
}

func (c tiflowOperatorConfig) ToHelmChart() (result *chart.Chart, err error) {
	result, err = loader.Load(c.helmChartPath)
	if err != nil {
		return nil, fmt.Errorf("failed to load helm chart %q: %w", c.helmChartPath, err)
	}
	return
}

func (c *tiflowOperatorConfig) GetCRDs() ([]*apiextensionsv1.CustomResourceDefinition, error) {
	var result []*apiextensionsv1.CustomResourceDefinition
	for _, path := range c.crdPaths {
		crd, err := helm.LoadCRD(path)
		if err != nil {
			return nil, err
		}
		result = append(result, crd...)
	}
	return result, nil
}

type TiflowOperator struct {
	task.BaseTask
	config *tiflowOperatorConfig
}

// NewTiflowOperator installs the TiDB operator from Helm charts. No need to delete
// the operator as it will be deleted along with the EKS cluster itself, i.e.
// no external resource is provisioned.
func NewTiflowOperator(ctx *task.Context) *TiflowOperator {
	t := &TiflowOperator{
		BaseTask: task.BaseTask{Context: ctx},
		config: &tiflowOperatorConfig{
			crdPaths:      ctx.Config.Network.TiflowOperator.CRDPaths,
			helmChartPath: ctx.Config.Network.TiflowOperator.ChartPath,
			image:         ctx.Config.Network.TiflowOperator.TiflowOperatorImage,
		},
	}
	return t
}

func (t *TiflowOperator) Name() string {
	return "tiflow-operator"
}

func (t *TiflowOperator) Create(ctx context.Context) deploy.Result {
	return deploy.ErrorOrDone(helm.Apply(ctx, t.Remote, t.config))
}
