package labels

import (
	"fmt"
	"regexp"
	"strings"

	"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/"

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

	// LabelKeyTenant defines the label key of resources' tenant ID.
	LabelKeyTenant = TagLabelPrefix + "tenant"

	// LabelKeyProject defines the label key of resources' project ID.
	LabelKeyProject = TagLabelPrefix + "project"

	// LabelProviderType defines the label of providerType.
	LabelProviderType = "cloud.pingcap.com/provider-type"

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

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 GetTenantFromLabels(labels map[string]string) string {
	return labels[LabelKeyTenant]
}

func GetProjectFromLabels(labels map[string]string) string {
	return labels[LabelKeyProject]
}

func GetProviderTypeFromLabels(labels map[string]string) string {
	return labels[LabelProviderType]
}

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
}
