package labels

import (
	"fmt"
	"regexp"
	"strings"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"k8s.io/apimachinery/pkg/util/validation/field"
)

const (
	// TagLabelPrefix is a label namespace for tagging resources, all labels started under this domain will be
	// used as the resource tag if possible
	// e.g. `tags.tidbcloud.com/tenant: 1234` will tag all the resources belonged to the API object with `tenant: 123`
	TagLabelPrefix = "tags.tidbcloud.com/"

	// LabelTenantID, LabelProjectID defines labels to identify a cluster.
	LabelTenantID        = TagLabelPrefix + "tenant"
	LabelProjectID       = TagLabelPrefix + "project"
	LabelEncryptKeyspace = TagLabelPrefix + "encrypt-keyspace"

	// LabelKeyKubernetesCluster defines label key of which kubernetes cluster
	// will be chosen to deploy infra api.
	LabelKeyKubernetesCluster = TagLabelPrefix + "kubernetes"

	// IgnoreBillingPrefix ignore billing prefix tag key
	IgnoreBillingPrefix = "billing"

	NameLabelKey               = "app.kubernetes.io/name"
	ComponentLabelKey          = "app.kubernetes.io/component"
	InstanceLabelKey           = "app.kubernetes.io/instance"
	ManagedByKey               = "app.kubernetes.io/managed-by"
	TidbPodComponentLabelValue = "serverless-tidb"
	TidbPodNameLabelValue      = "tidb-cluster"

	PrometheusIOScrapeLabel = "prometheus.io/scrape"
	PrometheusIOPathLabel   = "prometheus.io/path"
	PrometheusIOPortLabel   = "prometheus.io/port"

	ServerlessComponentNodeLabelKey = "serverless.tidbcloud.com/node"
	ServerlessNodeGroupLabelKey     = "serverless.tidbcloud.com/nodegroup"
	ServerlessZoneLabelKey          = "serverless.tidbcloud.com/zone"

	ServerlessDedicatedNodeCpuNumKey = "dedicated-node-cpu-num"

	ZREvicterIgnoredKey      = "zr-evicter.tidbcloud.com/ignored"
	ZREvicterPVCEvictableKey = "zr-evicter.tidbcloud.com/pvc-evictable"

	NodeDrainerCapacityTypeLabelKey = "nodedrainer.tidbcloud.com/capacityType"
	NodeDrainerCapacityTypeOnDemand = "ON_DEMAND"
	NodeDrainerCapacityTypeSpot     = "SPOT"
)

var (
	keyRegex   = regexp.MustCompile("^[a-z0-9-]{1,35}$")
	valueRegex = regexp.MustCompile("^[a-zA-Z0-9-]{1,35}$")
)

func GetKubeClusterFromLabels(labels map[string]string) string {
	return labels[LabelKeyKubernetesCluster]
}

func GetProviderTypeFromLabels(labels map[string]string) string {
	return labels[cloudv1.ProviderTypeLabel]
}

func NewKubeClusterLabels(labels map[string]string, kubeClusterName string) map[string]string {
	if labels == nil {
		labels = map[string]string{}
	}

	labels[LabelKeyKubernetesCluster] = kubeClusterName

	return labels
}

func TagsFromLabels(labels map[string]string) (map[string]string, field.ErrorList) {
	var allErrs field.ErrorList
	tags := map[string]string{}
	for k, v := range labels {
		if strings.HasPrefix(k, TagLabelPrefix) {
			key := k[len(TagLabelPrefix):]
			if strings.HasPrefix(key, IgnoreBillingPrefix) {
				continue
			}
			if !keyRegex.MatchString(key) {
				allErrs = append(allErrs, field.Invalid(field.NewPath(k), k,
					fmt.Sprintf("%q does not match %s", key, keyRegex.String())))
				continue
			}
			if !valueRegex.MatchString(v) {
				allErrs = append(allErrs, field.Invalid(field.NewPath(k), v,
					fmt.Sprintf("%q does not match %s", v, valueRegex.String())))
				continue
			}
			tags[k] = v
		}
	}
	return tags, allErrs
}
