package task

import (
	"context"

	"github.com/tidbcloud/eks-provider/pkg/config"
	"github.com/tidbcloud/eks-provider/pkg/deploy"
	"github.com/tidbcloud/eks-provider/pkg/helm"

	"helm.sh/helm/v3/pkg/chart"
	"helm.sh/helm/v3/pkg/chart/loader"

	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type CSI struct {
	*BaseTask
	config *csiConfig
}

type csiConfig struct {
	helmChartPath string

	driver              config.ImageConfig
	provisioner         config.ImageConfig
	attacher            config.ImageConfig
	livenessProbe       config.ImageConfig
	resizer             config.ImageConfig
	nodeDriverRegistrar config.ImageConfig
}

func (c *csiConfig) GetNamespace() string {
	return metav1.NamespaceSystem
}

func (c *csiConfig) ToHelmValues() map[string]interface{} {
	values := imageConfig(c.driver)
	values["sidecars"] = map[string]interface{}{
		"provisioner":         imageConfig(c.provisioner),
		"attacher":            imageConfig(c.attacher),
		"livenessProbe":       imageConfig(c.livenessProbe),
		"resizer":             imageConfig(c.resizer),
		"nodeDriverRegistrar": imageConfig(c.nodeDriverRegistrar),
	}
	values["enableVolumeResizing"] = true
	values["controller"] = map[string]interface{}{
		"serviceAccount": map[string]interface{}{
			"create": true,
		},
	}
	return values
}

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

func imageConfig(i config.ImageConfig) map[string]interface{} {
	return map[string]interface{}{
		"image": map[string]interface{}{
			"repository": i.Repo,
			"tag":        i.Tag,
		},
	}
}

func (c *csiConfig) GetName() string {
	return "csi"
}

func (c csiConfig) ToHelmChart() (result *chart.Chart, err error) {
	return loader.Load(c.helmChartPath)
}

func NewCSI(ctx *Context) *CSI {
	return &CSI{
		BaseTask: &BaseTask{Context: ctx},
		config: &csiConfig{
			helmChartPath:       ctx.Config.Network.CSI.ChartPath,
			driver:              ctx.Config.Network.CSI.Driver,
			provisioner:         ctx.Config.Network.CSI.Provisioner,
			attacher:            ctx.Config.Network.CSI.Attacher,
			livenessProbe:       ctx.Config.Network.CSI.LivenessProbe,
			resizer:             ctx.Config.Network.CSI.Resizer,
			nodeDriverRegistrar: ctx.Config.Network.CSI.NodeDriverRegistrar,
		},
	}
}

func (t *CSI) Name() string {
	return "CSI"
}

func (t *CSI) Create(ctx context.Context) deploy.Result {
	if t.remote == nil {
		return deploy.Skip("empty remote client")
	}
	return deploy.FromError(helm.Apply(ctx, t.remote, t.config))
}
