package aws

import (
	"context"
	"fmt"
	"sort"

	corev1 "k8s.io/api/core/v1"
	storagev1 "k8s.io/api/storage/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

	agentv2 "github.com/tidbcloud/observability/agent-control-server/api/v2"
	"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"
)

var (
	bindingMode   = storagev1.VolumeBindingWaitForFirstConsumer
	reclaimPolicy = corev1.PersistentVolumeReclaimDelete
)

type StorageClassTask struct {
	*reconciler.BaseTask[*agentv2.O11yK8sAgent]
}

func NewStorageClassTask(ctx *reconciler.Context[*agentv2.O11yK8sAgent]) *StorageClassTask {
	return &StorageClassTask{
		BaseTask: &reconciler.BaseTask[*agentv2.O11yK8sAgent]{Context: ctx},
	}
}

func (t *StorageClassTask) Name() string {
	return "StorageClass"
}

func (t *StorageClassTask) Create(ctx context.Context) deploy.Result {
	sc := &storagev1.StorageClass{
		ObjectMeta: metav1.ObjectMeta{
			Name: consts.MetricsAgentStorageClassName,
		},
		Parameters: map[string]string{
			"csi.storage.k8s.io/fstype": "ext4",
			"type":                      consts.AWSVolumeTypeGP3,
			"encrypted":                 "true",
			// Pass the tags to the persistent volumes
			// See https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/TAGGING.md for more information
			"tagSpecification": fmt.Sprintf("%s=%s", consts.CrossplaneKeyVendor, consts.CrossplaneValueVendor),
			"iops":             fmt.Sprintf("%d", consts.MetricsAgentGp3IOPS),
			"throughput":       fmt.Sprintf("%d", consts.MetricsAgentGp3ThroughputMBps),
		},
		VolumeBindingMode:    &bindingMode,
		AllowVolumeExpansion: ptr.To(true),
		ReclaimPolicy:        &reclaimPolicy,
		Provisioner:          "ebs.csi.aws.com",
		MountOptions:         []string{"nodelalloc,noatime"},
	}
	tags := map[string]string{
		consts.TagKeyBillingServiceType: "o11y",
		consts.TagKeyBillingTenant:      t.Agent.Spec.O11y.TenantID,
		consts.TagKeyBillingProject:     t.Agent.Spec.O11y.ProjectID,
		consts.TagKeyBillingUsedBy:      "o11y-agent",
	}
	// sort keys to make sure the order is consistent
	keys := make([]string, 0, len(tags))
	for key := range tags {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	cnt := 1
	for _, key := range keys {
		value := tags[key]
		tagKey := fmt.Sprintf("tagSpecification_%d", cnt)
		sc.Parameters[tagKey] = fmt.Sprintf("%s=%s", key, value)
		cnt++
	}
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	_, err = controllerutil.CreateOrUpdate(ctx, cli, sc, func() error { return nil })
	return deploy.PanicOrDone(err)
}
