package namer

import (
	"crypto/md5"
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestNamer(t *testing.T) {
	hash := func(ns, name string) string {
		s := fmt.Sprintf("%s/%s", ns, name)
		return fmt.Sprintf("%x", md5.Sum([]byte(s)))[:8]
	}

	tests := []struct {
		name     string
		meta     metav1.ObjectMeta
		options  []IdentifierOptions
		expected string
	}{
		{
			name: "basic usage with namespace",
			meta: metav1.ObjectMeta{
				Name:      "app",
				Namespace: "default",
			},
			expected: fmt.Sprintf("default-app-%s", hash("default", "app")),
		},
		{
			name: "basic usage without namespace",
			meta: metav1.ObjectMeta{
				Name: "app",
			},
			expected: fmt.Sprintf("app-%s", hash("", "app")),
		},
		{
			name: "with prefix",
			meta: metav1.ObjectMeta{
				Name:      "app",
				Namespace: "default",
			},
			options: []IdentifierOptions{
				WithPrefix("test"),
			},
			expected: fmt.Sprintf("test-default-app-%s", hash("default", "app")),
		},
		{
			name: "with prefix ending with dash",
			meta: metav1.ObjectMeta{
				Name:      "app",
				Namespace: "default",
			},
			options: []IdentifierOptions{
				WithPrefix("test-"),
			},
			expected: fmt.Sprintf("test-default-app-%s", hash("default", "app")),
		},
		{
			name: "with empty prefix",
			meta: metav1.ObjectMeta{
				Name:      "app",
				Namespace: "default",
			},
			options: []IdentifierOptions{
				WithPrefix(""),
			},
			expected: fmt.Sprintf("default-app-%s", hash("default", "app")),
		},
		{
			name: "long name truncation (default limit 63)",
			meta: metav1.ObjectMeta{
				Name:      "this-is-a-very-long-application-name-that-should-be-truncated-by-default",
				Namespace: "default",
			},
			// 63 - 9 = 54 chars for name part
			// "default-" + name
			// "default-this-is-a-very-long-application-name-that-should-be-truncated-by-default"
			// Truncated to 54 chars
			expected: fmt.Sprintf("%s-%s",
				"default-this-is-a-very-long-application-name-that-should-be-tr"[:54],
				hash("default", "this-is-a-very-long-application-name-that-should-be-truncated-by-default"),
			),
		},
		{
			name: "with custom limit (shorter than default)",
			meta: metav1.ObjectMeta{
				Name:      "app",
				Namespace: "default",
			},
			options: []IdentifierOptions{
				WithLimit(20),
			},
			// limit 20 -> name part limit = 20 - 9 = 11
			// "default-app" is 11 chars exactly.
			expected: fmt.Sprintf("default-app-%s", hash("default", "app")),
		},
		{
			name: "with custom limit causing truncation",
			meta: metav1.ObjectMeta{
				Name:      "long-app-name",
				Namespace: "default",
			},
			options: []IdentifierOptions{
				WithLimit(20),
			},
			// limit 20 -> name part limit = 11
			// "default-long-app-name" -> "default-lon" (11 chars)
			expected: fmt.Sprintf("default-lon-%s", hash("default", "long-app-name")),
		},
		{
			name: "prefix and limit combined",
			meta: metav1.ObjectMeta{
				Name:      "app",
				Namespace: "default",
			},
			options: []IdentifierOptions{
				WithPrefix("p"),
				WithLimit(20),
			},
			// "p-default-app" -> 13 chars
			// limit 20 -> name part limit 11
			// "p-default-app" -> "p-default-a"
			expected: fmt.Sprintf("p-default-a-%s", hash("default", "app")),
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := UniqueIdentifier(tt.meta, tt.options...)
			assert.Equal(t, tt.expected, got)
			assert.LessOrEqual(t, len(got), 63, "identifier should not exceed Kubernetes label limit (63)")
		})
	}
}
