package robot

import (
	"math/rand/v2"
	"strconv"

	"scrabble/backend/internal/engine"
)

// This file holds the wide, multi-locale corpus and the generator that gives each
// auto-match robot a fresh, per-game display name (composeRandomName, reached through
// Service.PickNamed). It is deliberately separate from the seeding pools in names.go:
// those are a fixed 32-per-language set bound 1:1 to the durable robot accounts (a
// stable fallback name), whereas this corpus only sources throwaway per-game names and
// can grow freely. Because the chosen name is stored on the seat rather than on the
// account, the small pool of accounts presents as an ever-changing crowd of opponents.
//
// Every composed name stays within account.ValidateDisplayName's editable format
// (Unicode letters, single "." / "_" separators, an optional trailing run of up to five
// digits), so a disguised robot remains indistinguishable from a human
// (docs/ARCHITECTURE.md §7). A Russian-variant game draws Cyrillic names with at most
// latinShareInRussian% Latin and never a CJK script; an English game draws the full
// international corpus (Western Latin names, native Japanese/Chinese names, Latin handles).

// nickSharePercent is the share of per-game names rendered as a handle (e.g.
// "DarkWolf07") rather than a person's real name.
const nickSharePercent = 35

// cjkShareIntl is the share of an international game's real names rendered in a native
// Japanese or Chinese script; the remainder are Western Latin names.
const cjkShareIntl = 25

// composeRandomName builds a fresh display name appropriate to the game variant (see
// the file overview for the routing). The result always satisfies
// account.ValidateDisplayName.
func composeRandomName(variant engine.Variant) string {
	if variant == engine.VariantRussianScrabble || variant == engine.VariantErudit {
		if rand.IntN(100) < latinShareInRussian {
			return latinPersona()
		}
		return cyrillicPersona()
	}
	return intlPersona()
}

// cyrillicPersona returns a Cyrillic real name or handle.
func cyrillicPersona() string {
	if rand.IntN(100) < nickSharePercent {
		return cyrillicNick()
	}
	return cyrillicReal()
}

// latinPersona returns a Western Latin real name or handle (also the Latin minority of
// Russian games and the handles of international games).
func latinPersona() string {
	if rand.IntN(100) < nickSharePercent {
		return latinNick()
	}
	return latinReal()
}

// intlPersona returns an international name: a Latin handle, a native Japanese/Chinese
// real name, or a Western Latin real name.
func intlPersona() string {
	if rand.IntN(100) < nickSharePercent {
		return latinNick()
	}
	if rand.IntN(100) < cjkShareIntl {
		return cjkReal()
	}
	return latinReal()
}

// latinReal composes a Western full name within a single locale so it reads naturally.
func latinReal() string {
	loc := latinLocales[rand.IntN(len(latinLocales))]
	first := loc.first[rand.IntN(len(loc.first))]
	surname := loc.surnames[rand.IntN(len(loc.surnames))]
	return composeName(first, surname, rand.IntN(3))
}

// cyrillicReal composes a Russian full name, agreeing the surname form with the first
// name's grammatical gender, in one of the three rendering forms.
func cyrillicReal() string {
	fn := firstNamesRUWide[rand.IntN(len(firstNamesRUWide))]
	sp := surnamesRUWide[rand.IntN(len(surnamesRUWide))]
	surname := sp.m
	if fn.female {
		surname = sp.f
	}
	return composeName(fn.name, surname, rand.IntN(3))
}

// cjkReal composes a native Japanese or Chinese name.
func cjkReal() string {
	if rand.IntN(2) == 0 {
		return japaneseName()
	}
	return chineseName()
}

// japaneseName composes a Japanese name: family-then-given (space-joined), or a bare
// family or given name as a handle.
func japaneseName() string {
	family := jpSurnames[rand.IntN(len(jpSurnames))]
	given := jpGiven[rand.IntN(len(jpGiven))]
	switch rand.IntN(10) {
	case 0, 1, 2:
		return given
	case 3:
		return family
	default:
		return family + " " + given
	}
}

// chineseName composes a Chinese name: family then given, written without a separator.
func chineseName() string {
	family := cnSurnames[rand.IntN(len(cnSurnames))]
	given := cnGiven[rand.IntN(len(cnGiven))]
	return family + given
}

// latinNick builds a Latin handle from the adjective and noun stem pools. English
// adjectives do not inflect, so any pairing reads naturally.
func latinNick() string {
	return assembleHandle(adjLatin[rand.IntN(len(adjLatin))], nounLatin[rand.IntN(len(nounLatin))])
}

// cyrillicNick builds a Cyrillic handle, agreeing the adjective's form with the noun's
// grammatical gender ("Дикий Волк", "Дикая Рысь").
func cyrillicNick() string {
	noun := nounCyr[rand.IntN(len(nounCyr))]
	adj := adjCyr[rand.IntN(len(adjCyr))]
	form := adj.m
	if noun.female {
		form = adj.f
	}
	return assembleHandle(form, noun.word)
}

// assembleHandle joins an adjective and noun into a handle: a bare noun, the two
// camel-cased ("DarkWolf"), or joined by a separator. Between two meaningful words a human
// almost always uses "_" — a "." there is a rare tell — so the separator is an underscore
// far more often than a dot. An optional trailing number may follow.
func assembleHandle(adj, noun string) string {
	var base string
	switch rand.IntN(4) {
	case 0:
		base = noun // a bare noun
	case 1:
		base = adj + noun // camel-cased
	default:
		sep := "_"
		if rand.IntN(10) == 0 {
			sep = "." // a dot between two words is rare
		}
		base = adj + sep + noun
	}
	if rand.IntN(2) == 0 {
		base += nickNumber()
	}
	return base
}

// nickNumber returns a short trailing number a handle commonly carries — a single
// digit, a two-digit suffix, or a four-digit year — always within the validator's
// five-digit cap.
func nickNumber() string {
	switch rand.IntN(3) {
	case 0:
		return strconv.Itoa(rand.IntN(9) + 1) // 1–9
	case 1:
		return strconv.Itoa(rand.IntN(90) + 10) // 10–99
	default:
		return strconv.Itoa(rand.IntN(40) + 1985) // 1985–2024
	}
}

// latinLocale is one Western locale's first names and surnames, paired only within the
// locale so a composed full name reads naturally.
type latinLocale struct {
	first    []string
	surnames []string
}

// latinLocales are the Western (Latin-script) locales the international and Russian-Latin
// pools draw from: English (reusing the seeding pools), German, Spanish, Italian,
// French, Portuguese.
var latinLocales = []latinLocale{
	{first: firstNamesFullEN, surnames: surnamesEN},
	{ // German
		first:    []string{"Lukas", "Leon", "Finn", "Jonas", "Felix", "Maximilian", "Paul", "Elias", "Noah", "Ben", "Klaus", "Wolfgang", "Hannah", "Emma", "Mia", "Sofia", "Lena", "Marie", "Laura", "Greta", "Ingrid", "Stefan"},
		surnames: []string{"Müller", "Schmidt", "Schneider", "Fischer", "Weber", "Meyer", "Wagner", "Becker", "Hoffmann", "Koch", "Richter", "Bauer", "Klein", "Wolf", "Schröder", "Neumann", "Braun", "Werner", "Krüger", "Hartmann", "Lange", "Schulze"},
	},
	{ // Spanish
		first:    []string{"Mateo", "Hugo", "Martín", "Lucas", "Daniel", "Pablo", "Álvaro", "Diego", "Javier", "Carlos", "Lucía", "Sofía", "María", "Martina", "Paula", "Valeria", "Carmen", "Elena", "Sara", "Pilar", "Andrés", "Sergio"},
		surnames: []string{"García", "Martínez", "López", "Sánchez", "González", "Rodríguez", "Fernández", "Gómez", "Jiménez", "Ruiz", "Hernández", "Díaz", "Moreno", "Álvarez", "Romero", "Alonso", "Navarro", "Torres", "Ramos", "Serrano", "Castro", "Rubio"},
	},
	{ // Italian
		first:    []string{"Francesco", "Alessandro", "Lorenzo", "Mattia", "Andrea", "Leonardo", "Gabriele", "Riccardo", "Tommaso", "Matteo", "Sofia", "Giulia", "Aurora", "Alice", "Emma", "Giorgia", "Martina", "Chiara", "Giuseppe", "Marco", "Roberto", "Stefano"},
		surnames: []string{"Rossi", "Russo", "Ferrari", "Esposito", "Bianchi", "Romano", "Colombo", "Ricci", "Marino", "Greco", "Bruno", "Gallo", "Conti", "Costa", "Giordano", "Mancini", "Rizzo", "Lombardi", "Moretti", "Barbieri", "Fontana", "Caruso"},
	},
	{ // French
		first:    []string{"Gabriel", "Louis", "Raphaël", "Jules", "Adam", "Arthur", "Nathan", "Léo", "Emma", "Jade", "Louise", "Alice", "Chloé", "Léa", "Manon", "Camille", "Pierre", "Sophie", "Julien", "Céline", "Antoine", "Claire"},
		surnames: []string{"Martin", "Bernard", "Dubois", "Robert", "Richard", "Petit", "Durand", "Leroy", "Moreau", "Simon", "Laurent", "Lefebvre", "Michel", "Bertrand", "Roux", "Vincent", "Fournier", "Morel", "Girard", "Mercier", "Lambert", "Bonnet"},
	},
	{ // Portuguese
		first:    []string{"João", "Pedro", "Tiago", "Miguel", "Tomás", "Rodrigo", "Diogo", "Afonso", "Duarte", "Maria", "Leonor", "Matilde", "Beatriz", "Carolina", "Mariana", "Inês", "Sofia", "Lara", "António", "Rita", "Catarina", "Bruno"},
		surnames: []string{"Silva", "Santos", "Ferreira", "Pereira", "Oliveira", "Costa", "Rodrigues", "Martins", "Sousa", "Fernandes", "Gonçalves", "Gomes", "Lopes", "Marques", "Alves", "Almeida", "Ribeiro", "Pinto", "Carvalho", "Teixeira", "Moreira", "Correia"},
	},
}

// jpSurnames and jpGiven are common Japanese family and given names in kanji.
var jpSurnames = []string{
	"佐藤", "鈴木", "高橋", "田中", "渡辺", "伊藤", "山本", "中村", "小林", "加藤",
	"吉田", "山田", "山口", "松本", "井上", "木村", "斎藤", "清水", "山崎", "池田",
	"橋本", "阿部",
}

var jpGiven = []string{
	"大翔", "蓮", "陽翔", "悠真", "颯太", "湊", "翔太", "大和", "健太", "樹",
	"葵", "陽菜", "凛", "結衣", "美咲", "優奈", "七海", "真央", "愛", "杏",
}

// cnSurnames and cnGiven are common Chinese family and given names in Han characters.
var cnSurnames = []string{
	"王", "李", "张", "刘", "陈", "杨", "黄", "赵", "周", "吴",
	"徐", "孙", "胡", "朱", "高", "林", "何", "郭", "马", "罗",
	"梁", "宋", "郑", "韩",
}

var cnGiven = []string{
	"伟", "芳", "娜", "敏", "静", "丽", "强", "磊", "军", "洋",
	"勇", "艳", "杰", "娟", "涛", "明", "超", "霞", "刚", "婷",
	"秀英", "建华",
}

// adjLatin and nounLatin are the adjective and noun stems for Latin handles.
var adjLatin = []string{
	"Dark", "Night", "Shadow", "Frost", "Silent", "Swift", "Wild", "Royal", "Lucky", "Crimson",
	"Mystic", "Cosmic", "Epic", "Noble", "Brave", "Lone", "Iron", "Steel", "Golden", "Silver",
	"Neon", "Cyber", "Turbo", "Rapid", "Hidden", "Frozen", "Electric", "Savage",
}

var nounLatin = []string{
	"Wolf", "Fox", "Raven", "Tiger", "Eagle", "Dragon", "Falcon", "Hawk", "Lion", "Bear",
	"Panther", "Viper", "Cobra", "Shark", "Phoenix", "Knight", "Ranger", "Hunter", "Rider", "Ghost",
	"Phantom", "Comet", "Nova", "Blade", "Arrow", "Storm", "Wizard", "Ninja",
}

// cyrAdjective is a Russian adjective in its masculine and feminine forms, so a handle's
// stem can agree with the gender of its noun.
type cyrAdjective struct{ m, f string }

// cyrNoun is a Russian noun for a handle, tagged feminine so the paired adjective agrees.
type cyrNoun struct {
	word   string
	female bool
}

// adjCyr and nounCyr are the adjective and noun stems for Cyrillic handles; cyrillicNick
// renders the adjective in the form that agrees with the chosen noun's gender.
var adjCyr = []cyrAdjective{
	{"Тёмный", "Тёмная"}, {"Ночной", "Ночная"}, {"Снежный", "Снежная"}, {"Лунный", "Лунная"},
	{"Звёздный", "Звёздная"}, {"Огненный", "Огненная"}, {"Ледяной", "Ледяная"}, {"Стальной", "Стальная"},
	{"Дикий", "Дикая"}, {"Тихий", "Тихая"}, {"Быстрый", "Быстрая"}, {"Гордый", "Гордая"},
	{"Грозный", "Грозная"}, {"Хитрый", "Хитрая"}, {"Смелый", "Смелая"}, {"Весёлый", "Весёлая"},
	{"Рыжий", "Рыжая"}, {"Серый", "Серая"}, {"Золотой", "Золотая"}, {"Дерзкий", "Дерзкая"},
	{"Лютый", "Лютая"}, {"Бравый", "Бравая"}, {"Мудрый", "Мудрая"}, {"Шальной", "Шальная"},
	{"Вольный", "Вольная"}, {"Яростный", "Яростная"}, {"Седой", "Седая"}, {"Жгучий", "Жгучая"},
}

var nounCyr = []cyrNoun{
	{"Волк", false}, {"Лис", false}, {"Ворон", false}, {"Тигр", false}, {"Орёл", false},
	{"Дракон", false}, {"Сокол", false}, {"Ястреб", false}, {"Лев", false}, {"Медведь", false},
	{"Барс", false}, {"Кот", false}, {"Кит", false}, {"Странник", false}, {"Охотник", false},
	{"Рыцарь", false}, {"Маг", false}, {"Призрак", false}, {"Воин", false}, {"Клинок", false},
	{"Ветер", false}, {"Гром", false}, {"Шторм", false}, {"Пилот", false}, {"Капитан", false},
	{"Мастер", false}, {"Енот", false},
	{"Комета", true}, {"Звезда", true}, {"Молния", true}, {"Пантера", true}, {"Рысь", true},
	{"Буря", true}, {"Сова", true}, {"Акула", true},
}

// firstNamesRUWide is a broad pool of Russian first names — full and colloquial forms
// mixed, each tagged by grammatical gender — for the per-game generator (wider than the
// 32-slot seeding pool in names.go).
var firstNamesRUWide = []genderedName{
	{"Александр", false}, {"Саша", false}, {"Дмитрий", false}, {"Дима", false},
	{"Сергей", false}, {"Серёжа", false}, {"Алексей", false}, {"Лёша", false},
	{"Михаил", false}, {"Миша", false}, {"Николай", false}, {"Коля", false},
	{"Владимир", false}, {"Володя", false}, {"Константин", false}, {"Костя", false},
	{"Павел", false}, {"Паша", false}, {"Андрей", false}, {"Андрюша", false},
	{"Иван", false}, {"Ваня", false}, {"Пётр", false}, {"Петя", false},
	{"Роман", false}, {"Рома", false}, {"Антон", false}, {"Евгений", false},
	{"Женя", false}, {"Максим", false}, {"Кирилл", false}, {"Артём", false},
	{"Анна", true}, {"Аня", true}, {"Мария", true}, {"Маша", true},
	{"Анастасия", true}, {"Настя", true}, {"Наталья", true}, {"Наташа", true},
	{"Татьяна", true}, {"Таня", true}, {"Екатерина", true}, {"Катя", true},
	{"Юлия", true}, {"Юля", true}, {"Ольга", true}, {"Оля", true},
	{"Елена", true}, {"Лена", true}, {"Ирина", true}, {"Ира", true},
	{"Светлана", true}, {"Света", true}, {"Дарья", true}, {"Даша", true},
	{"София", true}, {"Соня", true}, {"Полина", true}, {"Алина", true},
	{"Вера", true}, {"Ксения", true},
}

// surnamesRUWide is a broad pool of Russian surnames in masculine and feminine forms
// for the per-game generator.
var surnamesRUWide = []surnamePair{
	{"Иванов", "Иванова"}, {"Смирнов", "Смирнова"}, {"Кузнецов", "Кузнецова"},
	{"Соколов", "Соколова"}, {"Попов", "Попова"}, {"Лебедев", "Лебедева"},
	{"Новиков", "Новикова"}, {"Морозов", "Морозова"}, {"Волков", "Волкова"},
	{"Зайцев", "Зайцева"}, {"Павлов", "Павлова"}, {"Беляев", "Беляева"},
	{"Орлов", "Орлова"}, {"Громов", "Громова"}, {"Суханов", "Суханова"},
	{"Киселёв", "Киселёва"}, {"Макаров", "Макарова"}, {"Фёдоров", "Фёдорова"},
	{"Никитин", "Никитина"}, {"Захаров", "Захарова"}, {"Борисов", "Борисова"},
	{"Королёв", "Королёва"}, {"Герасимов", "Герасимова"}, {"Пономарёв", "Пономарёва"},
	{"Григорьев", "Григорьева"}, {"Романов", "Романова"}, {"Виноградов", "Виноградова"},
	{"Богданов", "Богданова"}, {"Воробьёв", "Воробьёва"}, {"Сергеев", "Сергеева"},
	{"Кузьмин", "Кузьмина"}, {"Соловьёв", "Соловьёва"}, {"Васильев", "Васильева"},
	{"Михайлов", "Михайлова"}, {"Петров", "Петрова"}, {"Тарасов", "Тарасова"},
	{"Белов", "Белова"}, {"Комаров", "Комарова"}, {"Гусев", "Гусева"},
	{"Титов", "Титова"},
}
