package robot

import (
	"errors"
	"testing"

	"github.com/google/uuid"

	"scrabble/backend/internal/engine"
)

// TestComposeName covers the three rendering forms, including a Cyrillic initial.
func TestComposeName(t *testing.T) {
	cases := []struct {
		first, surname string
		form           int
		want           string
	}{
		{"Anna", "Carter", nameFormFirstOnly, "Anna"},
		{"Anna", "Carter", nameFormInitial, "Anna C."},
		{"Anna", "Carter", nameFormFull, "Anna Carter"},
		{"Маша", "Суханова", nameFormInitial, "Маша С."},
		{"Маша", "Суханова", nameFormFull, "Маша Суханова"},
	}
	for _, c := range cases {
		if got := composeName(c.first, c.surname, c.form); got != c.want {
			t.Errorf("composeName(%q,%q,%d) = %q, want %q", c.first, c.surname, c.form, got, c.want)
		}
	}
}

// TestNamePoolsPaired checks the full and colloquial first-name pools line up by
// index (so a slot's gender and person are consistent) and the surname forms differ.
func TestNamePoolsPaired(t *testing.T) {
	if len(firstNamesFullEN) != robotPoolSize || len(firstNamesShortEN) != robotPoolSize {
		t.Fatalf("EN first-name pools must each hold %d names", robotPoolSize)
	}
	if len(firstNamesFullRU) != robotPoolSize || len(firstNamesShortRU) != robotPoolSize {
		t.Fatalf("RU first-name pools must each hold %d names", robotPoolSize)
	}
	for i := range firstNamesFullRU {
		if firstNamesFullRU[i].female != firstNamesShortRU[i].female {
			t.Errorf("RU pair %d disagrees on gender: %q vs %q", i, firstNamesFullRU[i].name, firstNamesShortRU[i].name)
		}
	}
	for _, sp := range surnamesRU {
		if sp.m == sp.f {
			t.Errorf("RU surname forms should differ: %q", sp.m)
		}
	}
}

// TestRobotDisplayNames checks the generated pools are the right size, non-empty and
// deterministic — durable robot accounts must keep a stable name across restarts.
func TestRobotDisplayNames(t *testing.T) {
	en1, en2 := robotDisplayNamesEN(), robotDisplayNamesEN()
	ru1, ru2 := robotDisplayNamesRU(), robotDisplayNamesRU()
	if len(en1) != robotPoolSize || len(ru1) != robotPoolSize {
		t.Fatalf("pool sizes en=%d ru=%d, want %d", len(en1), len(ru1), robotPoolSize)
	}
	for i := range en1 {
		if en1[i] != en2[i] || ru1[i] != ru2[i] {
			t.Fatalf("pool not deterministic at %d: en %q/%q ru %q/%q", i, en1[i], en2[i], ru1[i], ru2[i])
		}
		if en1[i] == "" || ru1[i] == "" {
			t.Fatalf("empty composed name at index %d", i)
		}
	}
}

// TestPickVariantRouting checks English games draw the Latin pool and Russian games
// draw mostly Russian names with a Latin minority.
func TestPickVariantRouting(t *testing.T) {
	enID, ruID := uuid.New(), uuid.New()
	s := &Service{poolEN: []uuid.UUID{enID}, poolRU: []uuid.UUID{ruID}}
	for i := 0; i < 200; i++ {
		if got, err := s.Pick(engine.VariantEnglish); err != nil || got != enID {
			t.Fatalf("scrabble_en Pick = (%v, %v), want (%v, nil)", got, err, enID)
		}
	}
	var en, ru int
	for i := 0; i < 4000; i++ {
		got, err := s.Pick(engine.VariantRussianScrabble)
		if err != nil {
			t.Fatalf("scrabble_ru Pick: %v", err)
		}
		switch got {
		case enID:
			en++
		case ruID:
			ru++
		}
	}
	if ru <= en {
		t.Errorf("scrabble_ru names should dominate a Russian game: ru=%d en=%d", ru, en)
	}
	if en == 0 {
		t.Errorf("some Latin names should appear in Russian games (got 0 of 4000)")
	}
	// Эрудит routes like Russian Scrabble.
	if _, err := s.Pick(engine.VariantErudit); err != nil {
		t.Errorf("erudit_ru Pick: %v", err)
	}
}

// TestPickFallback checks an empty side falls back to the other pool and an empty pool
// errors.
func TestPickFallback(t *testing.T) {
	id := uuid.New()
	if got, err := (&Service{poolEN: []uuid.UUID{id}}).Pick(engine.VariantRussianScrabble); err != nil || got != id {
		t.Errorf("scrabble_ru fallback to EN = (%v, %v), want (%v, nil)", got, err, id)
	}
	if got, err := (&Service{poolRU: []uuid.UUID{id}}).Pick(engine.VariantEnglish); err != nil || got != id {
		t.Errorf("scrabble_en fallback to RU = (%v, %v), want (%v, nil)", got, err, id)
	}
	if _, err := (&Service{}).Pick(engine.VariantEnglish); !errors.Is(err, ErrNoRobotAvailable) {
		t.Errorf("empty pool err = %v, want ErrNoRobotAvailable", err)
	}
}
