package task

import (
	"fmt"
	"strings"

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

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/helm"
)

// CRRFDaemonConfig implements helm.Package for deploying the crrf-daemon chart.
type CRRFDaemonConfig struct {
	chartPath string
	backup    *cloudv1.Backup
	cluster   *cloudv1.Cluster

	// Fields populated from CRRFSpec
	crrfID            string
	upstreamStorage   string
	downstreamStorage string
	image             string // "repo:tag"

	// Derived from backup/cluster
	taskName string
	pdAddr   string
}

var _ helm.Package = &CRRFDaemonConfig{}

func (c *CRRFDaemonConfig) GetName() string {
	return fmt.Sprintf("crrf-daemon-%s", c.backup.Name)
}

func (c *CRRFDaemonConfig) GetNamespace() string {
	return cloudv1.ClusterPrefixId(c.cluster.Name)
}

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

func (c *CRRFDaemonConfig) ToHelmValues() map[string]interface{} {
	args := map[string]interface{}{
		"upstreamStorage": c.upstreamStorage,
		"taskName":        c.taskName,
		"pdAddr":          c.pdAddr,
		"statusAddr":      ":10081",
	}
	values := map[string]interface{}{
		"args": args,
	}

	if c.downstreamStorage != "" {
		args["downstreamStorage"] = c.downstreamStorage
	}

	if c.image != "" {
		// Split "repo:tag" so the helm template can render them separately.
		// Use LastIndex to handle registries with port (e.g. registry:5000/img:tag).
		repo := c.image
		tag := ""
		if i := strings.LastIndex(c.image, ":"); i != -1 {
			repo = c.image[:i]
			tag = c.image[i+1:]
		}
		values["image"] = map[string]interface{}{
			"repository": repo,
			"tag":        tag,
		}
	}

	return values
}

func (c *CRRFDaemonConfig) GetCRDs() ([]*apiextensionsv1.CustomResourceDefinition, error) {
	return nil, nil
}
