package labels

import (
	"strings"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/shared-provider/pkg/types"
)

const (
	LabelKeyUID       = types.KeyPrefix + "uid"
	LabelKeyOwnedBy   = types.KeyPrefix + "owned-by"
	LabelKeyNamespace = types.KeyPrefix + "namespace"
	LabelKeyName      = types.KeyPrefix + "name"
)

func GVKString(gvk *schema.GroupVersionKind) string {
	if len(gvk.Group) > 0 {
		return gvk.Group + "." + gvk.Version + "." + strings.ToLower(gvk.Kind)
	}

	return gvk.Version + "." + strings.ToLower(gvk.Kind)
}

func NewOwnerLabels(owner client.Object, labels map[string]string) map[string]string {
	gvk := owner.GetObjectKind().GroupVersionKind()
	namespace := owner.GetNamespace()
	name := owner.GetName()
	uid := string(owner.GetUID())

	if labels == nil {
		labels = map[string]string{}
	}

	labels[LabelKeyOwnedBy] = GVKString(&gvk)
	labels[LabelKeyNamespace] = namespace
	labels[LabelKeyName] = name
	labels[LabelKeyUID] = uid

	return labels
}

func MatchOwnerLabels(owner client.Object, labels map[string]string) (isOwned bool, isMatched bool) {
	if labels == nil {
		return false, false
	}

	gvk := owner.GetObjectKind().GroupVersionKind()
	namespace := owner.GetNamespace()
	name := owner.GetName()
	uid := string(owner.GetUID())

	if !compareLabelKV(labels, LabelKeyOwnedBy, GVKString(&gvk)) {
		return false, false
	}
	if !compareLabelKV(labels, LabelKeyNamespace, namespace) {
		return false, false
	}
	if !compareLabelKV(labels, LabelKeyName, name) {
		return false, false
	}
	if !compareLabelKV(labels, LabelKeyUID, uid) {
		return true, false
	}

	return true, true
}

func GetOwnerFromLabels(labels map[string]string) (string, string, string, string) {
	if labels == nil {
		return "", "", "", ""
	}
	ownedBy := labels[LabelKeyOwnedBy]
	namespace := labels[LabelKeyNamespace]
	name := labels[LabelKeyName]
	uid := labels[LabelKeyUID]

	return ownedBy, namespace, name, uid
}

// labels should always not nil before call this function.
func compareLabelKV(labels map[string]string, key string, val string) bool {
	lval, ok := labels[key]
	if !ok || lval != val {
		return false
	}

	return true
}
