package utils

import (
	"crypto/md5"
	"fmt"
	"hash/fnv"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	lengthLimit = 63
	hashSize    = 8
	resultLimit = lengthLimit - hashSize - 1
)

func FnvHash8(raw string) string {
	hash := fnv.New32()
	// fnv.New32().Write() never return error
	_, _ = hash.Write([]byte(raw))
	return fmt.Sprintf("%x", hash.Sum32())
}

func UniqueIdentifierLte63(raw string) string {
	hash := FnvHash8(raw)
	if len(raw) > resultLimit {
		raw = raw[:resultLimit]
	}
	return fmt.Sprintf("%s-%s", raw, hash)
}

func UniqueIdentifierLte63V2(rawName string) string {
	if len(rawName) <= lengthLimit {
		return rawName
	}
	prefix := rawName[:resultLimit]
	suffix := FnvHash8(rawName)
	return fmt.Sprintf("%s-%s", prefix, suffix)
}

const (
	length32 = 32
	index23  = 23
)

func UniqueIdentifierLte32(raw string) string {
	if len(raw) <= length32 {
		return raw
	}
	prefix := raw[:index23]
	suffix := FnvHash8(raw)
	return fmt.Sprintf("%s-%s", prefix, suffix)
}

// UniqueIdentifierV2 copied from https://github.com/tidbcloud/infra-provider/blob/main/pkg/namer/namer.go#L385
func UniqueIdentifierV2(meta metav1.Object) string {
	namespacedName := fmt.Sprintf("%s/%s", meta.GetNamespace(), meta.GetName())
	hash := fmt.Sprintf("%x", md5.Sum([]byte(namespacedName)))[:hashSize]

	// The 8-digit hash will not be trimmed. Keep the namespaced name if possible
	result := meta.GetName()
	if meta.GetNamespace() != "" {
		result = fmt.Sprintf("%s-%s", meta.GetNamespace(), meta.GetName())
	}
	if len(result) > resultLimit {
		result = result[:resultLimit]
	}
	return fmt.Sprintf("%s-%s", result, hash)
}
