package main

import (
	"fmt"
	"os"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
)

func main() {
	loadWayfarerGalaxySeed()
	loadCustomWayfarerQuests()

	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "-h", "--help":
			SetLanguage(LangRU)
			printHelp()
			return
		case "--help-en":
			SetLanguage(LangEN)
			printHelp()
			return
		case "-sim":
			runSimulation()
			return
		case "-sim-durak":
			runDurakSimulation()
			return
		case "-sim-blackjack":
			runBlackjackSimulation()
			return
		case "-sim-101":
			runOneOhOneSimulation()
			return
		case "-sim-1000":
			runThousandSimulation()
			return
		}
	}

	p := tea.NewProgram(NewAppModel())
	if _, err := p.Run(); err != nil {
		fmt.Printf("ошибка TUI: %v\n", err)
		os.Exit(1)
	}
}

// printHelp выводит общее описание запуска и правила всех игр из
// реестра на текущем языке (см. SetLanguage) — доступно без захода
// в TUI, годится для чтения через `go-games-collection --help |
// less` или на непривычной к TUI системе.
func printHelp() {
	fmt.Println(asciiBanner)
	fmt.Println(T("app.subtitle"))
	fmt.Println()
	if CurrentLang() == LangEN {
		fmt.Println("USAGE")
		fmt.Println("  go-games-collection                open the collection menu")
		fmt.Println("  go-games-collection -sim           headless Tonk bot simulation (no TUI)")
		fmt.Println("  go-games-collection -sim-durak     same, for Durak")
		fmt.Println("  go-games-collection -sim-blackjack same, for Blackjack")
		fmt.Println("  go-games-collection -sim-101       same, for 101")
		fmt.Println("  go-games-collection -sim-1000      same, for 1000 (Thousand)")
		fmt.Println("  go-games-collection --help         show this help and rules in Russian")
		fmt.Println("  go-games-collection --help-en      show this help and rules in English")
	} else {
		fmt.Println("ЗАПУСК")
		fmt.Println("  go-games-collection                открыть меню коллекции")
		fmt.Println("  go-games-collection -sim           headless-симуляция ботов Тонка (без TUI)")
		fmt.Println("  go-games-collection -sim-durak     headless-симуляция ботов Дурака (без TUI)")
		fmt.Println("  go-games-collection -sim-blackjack headless-симуляция ботов Блэкджека (без TUI)")
		fmt.Println("  go-games-collection -sim-101       headless-симуляция ботов 101 (без TUI)")
		fmt.Println("  go-games-collection -sim-1000      headless-симуляция ботов 1000 (без TUI)")
		fmt.Println("  go-games-collection --help         показать эту справку и правила на русском")
		fmt.Println("  go-games-collection --help-en      показать эту справку и правила на английском")
	}
	fmt.Println()
	for _, g := range gameRegistry {
		name := g.Name()
		separator := strings.Repeat("=", len(name)+4)
		fmt.Println(separator)
		fmt.Printf("  %s\n", name)
		fmt.Println(separator)
		fmt.Println()
		fmt.Println(g.Rules())
	}
}

// runSimulation — headless-прогон партии из 4 ботов разного
// уровня, без TUI. Полезно для быстрой проверки баланса и
// поведения ботов: `go run . -sim`.
func runSimulation() {
	names, bots := newBotRoster(4)
	g := NewGame(names, -1)

	const maxTurns = 500
	for turn := 0; turn < maxTurns && g.Phase != PhaseGameOver; turn++ {
		bot := bots[g.CurrentPlayer]
		if err := bot.PlayTurn(g); err != nil {
			fmt.Printf("ошибка на ходу %s: %v\n", g.Players[g.CurrentPlayer].Name, err)
			break
		}
	}

	if g.Result == nil {
		fmt.Println("партия не завершилась за отведённое число ходов")
		return
	}

	switch {
	case g.Result.DeadRound:
		fmt.Printf("раунд закончился вничью: колода и сброс исчерпаны (банк %d возвращён игрокам)\n", g.Result.Pot)
	case g.Result.TonkCall:
		fmt.Printf("%s объявил(а) Тонк и забрал(а) банк ×%d (%d)!\n", g.Players[g.Result.Winner].Name, g.TonkMultiplier, g.Result.Pot*g.TonkMultiplier)
	default:
		fmt.Printf("%s избавился(лась) от всех карт и забрал(а) банк (%d)!\n", g.Players[g.Result.Winner].Name, g.Result.Pot)
	}
	for i, p := range g.Players {
		fmt.Printf("  %-20s изменение капитала: %+d (итого: %d)\n", p.Name, g.Result.BalanceDeltas[i], p.Balance)
	}
}

// runDurakSimulation — headless-прогон партии Дурака ботами, без
// TUI: `go run . -sim-durak`. Число игроков фиксировано (4) для
// простоты; для проверки других раскладов используйте TUI.
func runDurakSimulation() {
	names := newDurakBotNames(4)
	g := NewDurakGame(names, -1)
	bot := DurakBot{}

	const maxSteps = 10000
	steps := 0
	for ; steps < maxSteps && g.Phase != DurakPhaseGameOver; steps++ {
		if err := bot.PlayFullTurn(g); err != nil {
			fmt.Printf("ошибка на шаге %d: %v\n", steps, err)
			return
		}
	}

	if g.Result == nil {
		fmt.Println("партия не завершилась за отведённое число шагов")
		return
	}

	switch {
	case g.Result.Stalemate:
		fmt.Println("партия зашла в тупик и принудительно завершена вничью")
	case g.Result.NoLoser:
		fmt.Println("ничья: все избавились от карт одновременно")
	default:
		fmt.Printf("%s остался(лась) с картами на руках — дурак!\n", g.Players[g.Result.Loser].Name)
	}
	for _, p := range g.Players {
		status := "в игре"
		if p.Out {
			status = "отбился"
		}
		fmt.Printf("  %-10s карт: %-2d (%s)\n", p.Name, len(p.Hand), status)
	}
}

// runBlackjackSimulation — headless-прогон нескольких раундов
// блэкджека ботами, без TUI: `go run . -sim-blackjack`. Число
// игроков фиксировано (3) для простоты.
func runBlackjackSimulation() {
	names, _ := newBotRoster(3)
	g := NewBlackjackGame(names, -1, 1000, 10)
	bot := BlackjackBot{}

	const rounds = 5
	for round := 0; round < rounds; round++ {
		const maxSteps = 100
		for steps := 0; steps < maxSteps && g.Phase != BJPhaseRoundOver; steps++ {
			if err := bot.PlayFullTurn(g); err != nil {
				fmt.Printf("ошибка на шаге %d: %v\n", steps, err)
				return
			}
		}
		if g.Result == nil {
			fmt.Println("раунд не завершился за отведённое число шагов")
			return
		}

		fmt.Printf("--- Раунд %d --- дилер: %d", round+1, g.Result.DealerTotal)
		if g.Result.DealerBusted {
			fmt.Print(" (перебор)")
		}
		fmt.Println()
		for i, p := range g.Players {
			r := g.Result.PlayerResults[i]
			fmt.Printf("  %-10s %-10s изменение капитала: %+d (итого: %d)\n", p.Name, r.Outcome, r.Delta, p.Balance)
		}

		if round < rounds-1 {
			g = g.NextRound()
		}
	}
}

// runOneOhOneSimulation — headless-прогон полного матча 101
// ботами, без TUI: `go run . -sim-101`. Число игроков фиксировано
// (4) для простоты.
func runOneOhOneSimulation() {
	names := newOneOhOneBotNames(4)
	g := NewOneOhOneGame(names, -1)
	bot := OneOhOneBot{}

	const maxRounds = 200
	for round := 0; round < maxRounds; round++ {
		const maxSteps = 6000
		steps := 0
		for ; steps < maxSteps && g.Phase != OneOhOnePhaseRoundOver; steps++ {
			if err := bot.PlayFullTurn(g); err != nil {
				fmt.Printf("ошибка на шаге %d: %v\n", steps, err)
				return
			}
		}
		if g.Result == nil {
			fmt.Println("раунд не завершился за отведённое число шагов")
			return
		}

		if g.Result.Stalemate {
			fmt.Printf("--- Раунд %d: тупик, счёт не изменился ---\n", round+1)
		} else {
			winner := g.Players[g.Result.Winner].Name
			fmt.Printf("--- Раунд %d: %s избавился(лась) от карт первым(ой)", round+1, winner)
			if g.Result.QueenBonus {
				fmt.Print(" (бонус за даму!)")
			}
			fmt.Println()
			for i, p := range g.Players {
				fmt.Printf("  %-10s %+-4d очков за раунд (итого: %d)\n", p.Name, g.Result.ScoreDeltas[i], p.Score)
			}
		}

		if g.Result.MatchOver {
			if g.Result.NoWinner {
				fmt.Println("Партия завершилась без победителя.")
			} else {
				fmt.Printf("Партия окончена! Победитель: %s\n", g.Players[g.Result.MatchWinner].Name)
			}
			return
		}
		g.NextRound()
	}
	fmt.Println("матч не завершился за отведённое число раундов")
}

// runThousandSimulation — headless-прогон полного матча 1000
// ботами, без TUI: `go run . -sim-1000`.
func runThousandSimulation() {
	names := newThousandBotNames(3)
	g := NewThousandGame(names, -1)
	bot := ThousandBot{}

	const maxHands = 500
	for hand := 0; hand < maxHands; hand++ {
		const maxSteps = 2000
		steps := 0
		for ; steps < maxSteps && g.Phase != ThousandPhaseHandOver; steps++ {
			if err := bot.PlayFullTurn(g); err != nil {
				fmt.Printf("ошибка на шаге %d (фаза %v): %v\n", steps, g.Phase, err)
				return
			}
		}
		if g.Result == nil {
			fmt.Println("раздача не завершилась за отведённое число шагов")
			return
		}

		declarer := g.Players[g.Result.DeclarerIdx].Name
		status := "выполнил(а)"
		if !g.Result.Made {
			status = "не выполнил(а)"
		}
		fmt.Printf("--- Раздача %d: %s %s ставку %d ---\n", hand+1, declarer, status, g.Result.FinalBid)
		for i, p := range g.Players {
			fmt.Printf("  %-10s %+-5d очков (итого: %d)\n", p.Name, g.Result.ScoreDeltas[i], p.Score)
		}

		if g.Result.MatchOver {
			fmt.Printf("Партия окончена! Победитель: %s\n", g.Players[g.Result.MatchWinner].Name)
			return
		}
		g.NextHand()
	}
	fmt.Println("матч не завершился за отведённое число раздач")
}
