package main

import (
	"fmt"
	"testing"
)

func TestUrModelRollViaKey(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	m.game = NewUrGame(UrPlayerA)
	m.humanColor = UrPlayerA

	next, _ := m.Update(key("r"))
	m = next.(UrModel)
	if !m.game.Rolled && m.game.CurrentPlayer == UrPlayerA {
		t.Errorf("после броска Rolled должен был выставиться (или очередь смениться, если ходов нет)")
	}
}

func TestUrModelApplyMoveViaDigitKey(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	m.game = NewUrGame(UrPlayerA)
	m.humanColor = UrPlayerA
	m.game.Roll(3)
	if m.game.CurrentPlayer != UrPlayerA {
		t.Fatalf("тест предполагает ход человека")
	}

	next, _ := m.Update(key("1"))
	m = next.(UrModel)
	if m.isError {
		t.Fatalf("неожиданная ошибка: %s", m.message)
	}
	if m.game.Path[UrPlayerA][0] != 3 {
		t.Errorf("ожидалась позиция 3 после хода, получено %d", m.game.Path[UrPlayerA][0])
	}
}

func TestUrModelRejectsMoveKeyBeforeRoll(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	m.game = NewUrGame(UrPlayerA)
	m.humanColor = UrPlayerA

	next, _ := m.Update(key("1"))
	m = next.(UrModel)
	if m.game.Path[UrPlayerA][0] != 0 {
		t.Errorf("ход не должен был приняться до броска костей")
	}
}

func TestUrModelBotPlaysWhenNotHumanTurn(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	m.game = NewUrGame(UrPlayerB)
	m.humanColor = UrPlayerA

	next, _ := m.Update(botMoveMsg{})
	m = next.(UrModel)
	if m.game.CurrentPlayer != UrPlayerA {
		t.Errorf("после полного хода бота (без розеток) очередь должна была перейти к человеку")
	}
}

func TestUrModelIgnoresBotMoveMsgOnHumanTurn(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	m.game = NewUrGame(UrPlayerA)
	m.humanColor = UrPlayerA

	next, _ := m.Update(botMoveMsg{})
	m = next.(UrModel)
	if m.game.Rolled {
		t.Errorf("botMoveMsg не должно было ничего менять, пока сейчас ход человека")
	}
}

func TestUrModelQReturnsToMenuNotQuitsApp(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	next, _ := m.Update(key("q"))
	m = next.(UrModel)
	if !m.backToMenu {
		t.Errorf("ожидался флаг backToMenu после 'q'")
	}
	if m.quitting {
		t.Errorf("'q' не должно завершать приложение целиком")
	}
}

func TestUrModelActionsIgnoredAfterGameOver(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	m.game = NewUrGame(UrPlayerA)
	m.humanColor = UrPlayerA
	m.game.Result = &UrResult{Winner: UrPlayerA}

	next, _ := m.Update(key("r"))
	m = next.(UrModel)
	if m.game.Rolled {
		t.Errorf("действия после завершения партии не должны приниматься")
	}
}

func TestUrModelFullAutoPlaythrough(t *testing.T) {
	m := NewUrModel(UrDifficultyMedium, ColorChoiceA)
	m.game = NewUrGame(UrPlayerA)
	m.humanColor = UrPlayerA
	humanBot := UrBot{Difficulty: UrDifficultyMedium}

	steps := 0
	for m.game.Result == nil && steps < 20000 {
		steps++
		if m.game.CurrentPlayer != m.humanColor {
			next, _ := m.Update(botMoveMsg{})
			m = next.(UrModel)
			continue
		}
		if !m.game.Rolled {
			next, _ := m.Update(key("r"))
			m = next.(UrModel)
			continue
		}
		moves := m.game.LegalMoves()
		if len(moves) == 0 {
			t.Fatalf("LegalMoves пуст при Rolled=true для хода человека — не должно происходить")
		}
		if len(moves) > 9 {
			t.Fatalf("число легальных ходов превысило 9: %d", len(moves))
		}
		chosen := humanBot.DecideMove(m.game, m.rng)
		idx := -1
		for i, mv := range moves {
			if mv.PieceIdx == chosen {
				idx = i
				break
			}
		}
		if idx < 0 {
			idx = 0
		}
		next, _ := m.Update(key(fmt.Sprintf("%d", idx+1)))
		m = next.(UrModel)
		if m.isError {
			t.Fatalf("неожиданная ошибка при ходе: %s", m.message)
		}
	}
	if m.game.Result == nil {
		t.Fatalf("партия не завершилась за %d шагов", steps)
	}
}

func TestNewUrModelRespectsColorChoiceA(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
	if m.humanColor != UrPlayerA {
		t.Errorf("при выборе ColorChoiceA человек должен был играть за UrPlayerA, получено %v", m.humanColor)
	}
}

func TestNewUrModelRespectsColorChoiceB(t *testing.T) {
	m := NewUrModel(UrDifficultyEasy, ColorChoiceB)
	if m.humanColor != UrPlayerB {
		t.Errorf("при выборе ColorChoiceB человек должен был играть за UrPlayerB, получено %v", m.humanColor)
	}
}

func TestNewUrModelRandomColorGivesValidColor(t *testing.T) {
	seenA, seenB := false, false
	for i := 0; i < 50 && !(seenA && seenB); i++ {
		m := NewUrModel(UrDifficultyEasy, ColorChoiceRandom)
		if m.humanColor == UrPlayerA {
			seenA = true
		} else {
			seenB = true
		}
	}
	if !seenA || !seenB {
		t.Errorf("случайный выбор цвета должен был давать оба варианта за 50 попыток: A=%v B=%v", seenA, seenB)
	}
}
