package alicloud

import (
	"context"
	"fmt"
	"sort"
	"strings"

	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/controllers/kubernetesagent/metadata"
	"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.KubernetesAgent]
}

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

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

func (t *StorageClassTask) ClusterMeta() deploy.ClusterMeta {
	return metadata.ClusterMeta(t.Agent)
}

func (t *StorageClassTask) Create(ctx context.Context) deploy.Result {
	tagsMap := map[string]string{
		consts.TagKeyBillingServiceType: "o11y",
		consts.TagKeyBillingTenant:      t.Agent.Spec.O11y.TenantID,
		consts.TagKeyBillingUsedBy:      "o11y-agent",
		consts.CrossplaneKeyVendor:      consts.CrossplaneValueVendor,
	}
	// sort keys to make sure the order is consistent
	tagSlice := make([]string, 0, len(tagsMap))
	for k, v := range tagsMap {
		tagSlice = append(tagSlice, fmt.Sprintf("%s:%s", k, v))
	}
	sort.Strings(tagSlice)

	sc := &storagev1.StorageClass{
		ObjectMeta: metav1.ObjectMeta{
			Name: consts.MetricsAgentStorageClassName,
		},
		Parameters: map[string]string{
			"fstype":           "ext4",
			"type":             consts.AliCloudVolumeTypeESSD,
			"encrypted":        "true",
			"diskTags":         strings.Join(tagSlice, ","),
			"provisionedIops":  fmt.Sprintf("%d", consts.MetricsAgentGp3IOPS),
			"performanceLevel": "PL1",
		},
		VolumeBindingMode:    &bindingMode,
		AllowVolumeExpansion: ptr.To(true),
		ReclaimPolicy:        &reclaimPolicy,
		Provisioner:          "diskplugin.csi.alibabacloud.com",
		MountOptions:         []string{"nodelalloc,noatime"},
	}

	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)
}
