package utils

import (
	"strings"
	"testing"

	"github.com/google/uuid"
)

// TestGenerateID_ReturnsParseableNonEmptyUUID pins the post-#1425 contract:
// GenerateID never returns the empty string. The pre-#1425 implementation
// swallowed `uuid.NewRandom()` errors and returned `""`, which created
// a fail-open across the 40+ call sites (JWT JTI, record IDs, permission
// junction IDs, password placeholders). Empty-string return is now
// architecturally impossible — entropy failure panics instead, matching
// google/uuid's own `New()` / `NewString()` canonical behavior.
func TestGenerateID_ReturnsParseableNonEmptyUUID(t *testing.T) {
	id := GenerateID()
	if id == "" {
		t.Fatalf("GenerateID() returned empty string — entropy-failure swallow has regressed")
	}
	if _, err := uuid.Parse(id); err != nil {
		t.Fatalf("GenerateID() returned %q which does not parse as a UUID: %v", id, err)
	}
	if !IsValidUUID(id) {
		t.Fatalf("IsValidUUID(%q) = false, want true", id)
	}
}

// TestGenerateID_UniquePerCall guards against any future regression that
// would cache or otherwise reuse a single UUID — particularly critical
// for callers that use GenerateID for primary keys, JWT JTI, or password
// placeholders, where collisions would silently corrupt auth state.
func TestGenerateID_UniquePerCall(t *testing.T) {
	const n = 1024
	seen := make(map[string]struct{}, n)
	for i := 0; i < n; i++ {
		id := GenerateID()
		if _, dup := seen[id]; dup {
			t.Fatalf("GenerateID() produced duplicate %q within %d calls", id, n)
		}
		seen[id] = struct{}{}
	}
}

// TestGenerateID_VersionFour pins that GenerateID returns a Version 4
// (random) UUID — not a time-ordered v1 or namespaced v5 — because the
// security properties callers rely on (JTI unpredictability, password
// placeholder unguessability) require uniform randomness.
func TestGenerateID_VersionFour(t *testing.T) {
	id := GenerateID()
	parsed, err := uuid.Parse(id)
	if err != nil {
		t.Fatalf("GenerateID() returned %q which does not parse: %v", id, err)
	}
	if parsed.Version() != 4 {
		t.Fatalf("GenerateID() returned UUID version %d, want 4 (random)", parsed.Version())
	}
}

// TestIsValidUUID_RejectsCommonGarbage spot-checks IsValidUUID against
// inputs that callers must not treat as valid IDs.
func TestIsValidUUID_RejectsCommonGarbage(t *testing.T) {
	bad := []string{
		"",
		"not-a-uuid",
		"00000000-0000-0000-0000",     // truncated
		strings.Repeat("z", 36),        // right length, wrong charset
		"zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
	}
	for _, b := range bad {
		if IsValidUUID(b) {
			t.Fatalf("IsValidUUID(%q) = true, want false", b)
		}
	}
}
