package main

import "testing"

func TestUrNewGameAllPiecesInHand(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	for _, p := range [2]UrPlayer{UrPlayerA, UrPlayerB} {
		for i, pos := range g.Path[p] {
			if pos != 0 {
				t.Errorf("шашка %d игрока %v должна начинать в руке (0), получено %d", i, p, pos)
			}
		}
	}
}

func TestUrRollZeroEndsTurnImmediately(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	if err := g.Roll(0); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.CurrentPlayer != UrPlayerB {
		t.Errorf("бросок 0 должен был сразу передать ход сопернику")
	}
}

func TestUrCannotRollTwiceInOneTurn(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Roll(3)
	if err := g.Roll(2); err != ErrUrAlreadyRolled {
		t.Errorf("ожидалась ошибка повторного броска, получено: %v", err)
	}
}

func TestUrMoveRequiresRollFirst(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	if err := g.Move(0); err != ErrUrMustRollFirst {
		t.Errorf("ожидалась ошибка отсутствия броска, получено: %v", err)
	}
}

func TestUrEnterFromHand(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Roll(3)
	if err := g.Move(0); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.Path[UrPlayerA][0] != 3 {
		t.Errorf("ожидалась позиция 3 после входа с броском 3, получено %d", g.Path[UrPlayerA][0])
	}
}

func TestUrCaptureOnSharedSquareSendsToHand(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerA][0] = 4
	g.Path[UrPlayerB][0] = 7 // общая клетка (sharedIdx=2, не розетка)
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 3 // 4+3=7 — встаёт на шашку соперника

	if err := g.Move(0); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.Path[UrPlayerB][0] != 0 {
		t.Errorf("шашка соперника должна была вернуться в руку, получено %d", g.Path[UrPlayerB][0])
	}
	if g.Path[UrPlayerA][0] != 7 {
		t.Errorf("своя шашка должна была встать на клетку 7, получено %d", g.Path[UrPlayerA][0])
	}
}

func TestUrRosetteSquareBlocksCapture(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerA][0] = 4
	g.Path[UrPlayerB][0] = 8 // общая клетка sharedIdx=3 — это розетка (pathIndex 8)
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 4 // 4+4=8

	moves := g.LegalMoves()
	for _, mv := range moves {
		if mv.PieceIdx == 0 {
			t.Errorf("нельзя вставать на клетку с розеткой, занятую соперником")
		}
	}
}

func TestUrRosetteGrantsExtraTurn(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerA][0] = 4
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 4 // 4+4=8, розетка

	if err := g.Move(0); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.CurrentPlayer != UrPlayerA {
		t.Errorf("розетка должна была дать дополнительный ход тому же игроку")
	}
	if g.Rolled {
		t.Errorf("после хода, давшего доп.бросок, Rolled должен был сброситься для нового броска")
	}
}

func TestUrNonRosetteEndsTurn(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerA][0] = 4
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 2 // 4+2=6 — не розетка

	if err := g.Move(0); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.CurrentPlayer != UrPlayerB {
		t.Errorf("обычный (не розетка) ход должен был передать очередь сопернику")
	}
}

func TestUrExactRollRequiredToBearOff(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerA][0] = 13
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 3 // 13+3=16 > 15 — перелёт, недопустимо

	moves := g.LegalMoves()
	for _, mv := range moves {
		if mv.PieceIdx == 0 {
			t.Errorf("перелёт при снятии с доски не должен быть разрешён")
		}
	}
}

func TestUrExactRollBearsOff(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerA][0] = 13
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 2 // 13+2=15 — точное снятие

	if err := g.Move(0); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.Path[UrPlayerA][0] != UrPathLength+1 {
		t.Errorf("шашка должна была быть снята с доски (15), получено %d", g.Path[UrPlayerA][0])
	}
}

func TestUrWinWhenAllSevenBorneOff(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	for i := 0; i < UrPieceCount-1; i++ {
		g.Path[UrPlayerA][i] = UrPathLength + 1
	}
	g.Path[UrPlayerA][UrPieceCount-1] = 13
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 2

	if err := g.Move(UrPieceCount - 1); err != nil {
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.Result == nil || g.Result.Winner != UrPlayerA {
		t.Fatalf("ожидалась победа игрока A, получено Result=%+v", g.Result)
	}
}

func TestUrNoLegalMovesEndsTurnAfterRoll(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	for i := 0; i < UrPieceCount-1; i++ {
		g.Path[UrPlayerA][i] = UrPathLength + 1
	}
	g.Path[UrPlayerA][UrPieceCount-1] = 14
	g.CurrentPlayer = UrPlayerA

	if err := g.Roll(3); err != nil { // 14+3=17 — перелёт, нет легальных ходов
		t.Fatalf("неожиданная ошибка: %v", err)
	}
	if g.CurrentPlayer != UrPlayerB {
		t.Errorf("при отсутствии легальных ходов очередь должна была перейти к сопернику")
	}
}

func TestUrPrivateSquaresNeverConflictBetweenPlayers(t *testing.T) {
	g := NewUrGame(UrPlayerA)
	g.Path[UrPlayerB][0] = 2 // частная клетка B — не должна мешать A
	g.Path[UrPlayerA][0] = 0
	g.CurrentPlayer = UrPlayerA
	g.Rolled = true
	g.DiceValue = 2

	moves := g.LegalMoves()
	found := false
	for _, mv := range moves {
		if mv.PieceIdx == 0 {
			found = true
		}
	}
	if !found {
		t.Errorf("частная клетка соперника не должна мешать входу своей шашки на такую же по номеру собственную клетку")
	}
}
