package controllers

import (
	"context"
	"fmt"

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

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/config"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	eksconsts "github.com/tidbcloud/infra-provider/pkg/consts"
)

const MigratedToThreeLayerArchLabel = "dedicated.regionalserver.tidbcloud.com/migrated"

func GetNetworkSpec(ctx context.Context, cli client.Client, cluster *cloudv1.Cluster) (*cloudv1.Network, error) {
	network := new(cloudv1.Network)
	networkKey := cluster.GetNetworkRef()
	if err := cli.Get(ctx, networkKey, network); err != nil {
		return nil, err
	}
	return network, nil
}

func GetMaxConcurrentReconciles(cfg config.RootConfig, name string) int {
	maxConcurrentReconciles := eksconsts.DefaultMaxConcurrentReconciles
	if v, ok := cfg.MaxConcurrentReconciles[name]; ok {
		maxConcurrentReconciles = v
	}
	return maxConcurrentReconciles
}

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

// ConvertAWSStorageClass converts the AWS cloudv1.StorageClass to storagev1.StorageClass
func ConvertAWSStorageClass(sc cloudv1.StorageClass) *storagev1.StorageClass {
	params := map[string]string{
		"csi.storage.k8s.io/fstype": "ext4",
		"type":                      sc.Type,
		"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.TagKeyCrossplaneVendor, consts.TagValCrossplaneVendor),
	}
	// Only gp3, io1 and io2 support specifying iops parameter https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/parameters.md#supported-parameters
	if sc.Type == "gp3" || sc.Type == "io2" || sc.Type == "io1" {
		params["iops"] = fmt.Sprint(sc.IOPS)
	}
	// Only gp3 support specifying throughput parameter https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/parameters.md#supported-parameters
	if sc.Type == "gp3" {
		params["throughput"] = fmt.Sprint(sc.Throughput)
	}
	res := &storagev1.StorageClass{
		ObjectMeta: metav1.ObjectMeta{
			Name: sc.Name,
		},
		VolumeBindingMode:    &bindingMode,
		AllowVolumeExpansion: pointer.Bool(true),
		ReclaimPolicy:        &reclaimPolicy,
		Provisioner:          "ebs.csi.aws.com",
		Parameters:           params,
		MountOptions:         []string{"nodelalloc,noatime"},
	}
	if sc.Encryption != nil && sc.Encryption.AwsKMSARN != nil {
		res.Parameters["kmsKeyId"] = *sc.Encryption.AwsKMSARN
	}
	return res
}

// IsMigratedCR checks if the CR has been migrated to the three-layer architecture.
// Note that only network CRs may have the label.
func IsMigratedCR(obj client.Object) bool {
	labels := obj.GetLabels()
	if labels == nil {
		return false
	}
	return labels[MigratedToThreeLayerArchLabel] == "true"
}
