package eks

import (
	"context"

	"k8s.io/apimachinery/pkg/types"

	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/helm"
	"github.com/tidbcloud/infra-provider/pkg/namer"
	"github.com/tidbcloud/infra-provider/pkg/util"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task"
)

type ClusterAutoscaler struct {
	*task.BaseTask
	config *clusterAutoscalerConfig
}

type clusterAutoscalerConfig struct {
	config.InfraComponentConfig
	eksClusterName string
	region         string
}

func (c *clusterAutoscalerConfig) ToHelmValues() map[string]interface{} {
	values := map[string]interface{}{
		"region":         c.region,
		"eksClusterName": c.eksClusterName,
	}

	// Merge values that is determined during runtime with helm values defined in the config template.
	return util.MergeMaps(c.HelmValues, values)
}

func NewClusterAutoscaler(ctx *task.Context) *ClusterAutoscaler {
	t := &task.BaseTask{Context: ctx}

	return &ClusterAutoscaler{
		BaseTask: t,
		config: &clusterAutoscalerConfig{
			InfraComponentConfig: ctx.InfraTmplConfig.ClusterAutoscaler,
			region:               ctx.APPBox.Spec.Region,
		},
	}
}

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

func (t *ClusterAutoscaler) eksClusterName() string {
	eksName := namer.UniqueIdentifier(t.APPBox.ObjectMeta)
	if name := t.APPBox.Annotations[v1alpha1.AnnotationKeyOwnCrossplaneNameEKS]; name != "" {
		eksName = name
	}
	return eksName
}

func (t *ClusterAutoscaler) Create(ctx context.Context) deploy.Result {
	// just apply the chart again to existed cluster.
	if _, err := t.Remote.GetClient(ctx); err != nil {
		return deploy.Panic(err)
	}

	// to support the cluster autoscaler flags
	// https://github.com/tidbcloud/eks-bootstrap/blob/5e422f2cbccea5976708defb845cea3c38c1c94f/helm/aws-cluster-auto-scaler/templates/cluster-auto-discover.yaml#L180-L193
	//
	// - ./cluster-autoscaler
	// - --v=4
	// ...
	// - --scale-down-utilization-threshold=0.000001
	// {{-  if .Values.asgName }}
	// - --nodes={{ .Values.min }}:{{ .Values.max }}:{{ .Values.asgName }}{{- end}}
	// {{-  if .Values.eksClusterName }}
	// - --skip-nodes-with-system-pods=false
	// - --balance-similar-node-groups
	// - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,kubernetes.io/cluster/{{ .Values.eksClusterName }}{{- end}}
	//

	t.config.eksClusterName = t.eksClusterName()

	return deploy.ErrorOrDone(helm.Apply(ctx, t.Remote, t.config))
}

func (t *ClusterAutoscaler) PostCreate(ctx context.Context) deploy.Result {
	return deploy.ErrorOrDone(controllers.EnsureChartDeploymentReady(ctx, t.Remote, types.NamespacedName{
		Namespace: t.config.GetNamespace(),
		Name:      t.config.GetName(),
	}))
}
