from gungi.gungi import Gungi

CHECKMATE_FEN = (
    "3img3/1ra1|n:G|1as1/d1fwdwf2/9/8d/9/D1FWDWF1D/1SA1N1AR1/4MI3 J2N2S1R1D1/j2n2s1r1d1 b 1 - 3"
)
ESCAPE_FEN = (
    "3img3/1ra1N1as1/d1fw2f1d/4dw3/9/9/D1FWDWF1D/1SA3AR1/3GMI3 J2N2S1R1D1/j2n2s1r1d1 b 1 - 3"
)
NORMAL_FEN = (
    "3img3/1ra1n1as1/d1fwdwf1d/9/9/9/D1FWDWF1D/1SA1N1AR1/3GMI3 J2N2S1R1D1/j2n2s1r1d1 w 1 - 1"
)
DRAFT_FEN = "9/9/9/9/9/9/9/9/9 M1G1I1J2W2N3R2S2F2D4C1A2K1T1/m1g1i1j2w2n3r2s2f2d4c1a2k1t1 w 2 wb 1"
MARSHAL_CAPTURED_FEN = (
    "1|g:N|2|W:N|Ad1f/7r1/1nd2Adfr/2|c:G|j2K2/6s1D/1w|W:T|6/2F4J|F:D|/i8/2|S:w||R:M|3C1 "
    "-/- b 3 - 164"
)


def test_detects_checkmate():
    gungi = Gungi(CHECKMATE_FEN)
    assert gungi.is_checkmate() is True
    assert gungi.in_check() is True
    assert gungi.is_game_over() is True


def test_not_checkmate_when_escape_exists():
    gungi = Gungi(ESCAPE_FEN)
    assert gungi.is_checkmate() is False
    assert gungi.in_check() is True
    assert len(gungi.moves()) > 0


def test_not_checkmate_when_not_in_check():
    gungi = Gungi(NORMAL_FEN)
    assert gungi.is_checkmate() is False
    assert gungi.in_check() is False


def test_detects_stalemate():
    gungi = Gungi("8m/9/7DD/7C1/9/9/9/9/M8 -/- b 3 - 1")
    assert gungi.in_check() is False
    assert gungi.is_stalemate() is True
    assert gungi.is_draw() is True
    assert gungi.is_game_over() is True
    assert gungi.moves() == []


def test_not_stalemate_when_safe_moves_exist():
    gungi = Gungi(NORMAL_FEN)
    assert gungi.is_stalemate() is False
    assert len(gungi.moves()) > 0


def test_not_stalemate_when_in_check():
    gungi = Gungi(ESCAPE_FEN)
    assert gungi.in_check() is True
    assert gungi.is_stalemate() is False


def test_detects_insufficient_material_with_non_adjacent_marshals():
    gungi = Gungi("m8/9/9/9/9/9/9/9/8M -/- w 3 - 1")
    assert gungi.is_insufficient_material() is True
    assert gungi.is_draw() is True
    assert gungi.is_game_over() is True


def test_not_insufficient_material_for_adjacent_marshals():
    gungi = Gungi("mM7/9/9/9/9/9/9/9/9 -/- w 3 - 1")
    assert gungi.is_insufficient_material() is False


def test_not_insufficient_material_for_diagonal_marshals():
    gungi = Gungi("m8/1M7/9/9/9/9/9/9/9 -/- w 3 - 1")
    assert gungi.is_insufficient_material() is False


def test_not_insufficient_material_when_other_pieces_exist():
    gungi = Gungi("m8/9/9/9/9/9/9/9/8M D1/d1 w 3 - 1")
    assert gungi.is_insufficient_material() is False


def test_not_insufficient_material_with_single_marshal():
    gungi = Gungi("m8/9/9/9/9/9/9/9/9 -/- w 3 - 1")
    assert gungi.is_insufficient_material() is False


def test_not_insufficient_material_with_three_marshals():
    gungi = Gungi("mMm6/9/9/9/9/9/9/9/9 -/- w 3 - 1")
    assert gungi.is_insufficient_material() is False


def test_game_ending_helpers_return_false_during_draft():
    gungi = Gungi(DRAFT_FEN)
    assert gungi.in_draft() is True
    assert gungi.is_checkmate() is False
    assert gungi.is_stalemate() is False
    assert gungi.is_insufficient_material() is False
    assert gungi.is_game_over() is False


def test_marshal_captured_is_game_over_but_not_checkmate_or_stalemate():
    gungi = Gungi(MARSHAL_CAPTURED_FEN)
    assert gungi.is_game_over() is True
    assert gungi.is_checkmate() is False
    assert gungi.is_stalemate() is False


def test_moves_are_still_generated_while_in_check():
    gungi = Gungi(ESCAPE_FEN)
    assert gungi.in_check() is True
    assert len(gungi.moves()) > 0


def test_is_game_over_integration_cases():
    assert Gungi(CHECKMATE_FEN).is_game_over() is True
    assert Gungi("m8/9/9/9/9/9/9/9/8M -/- w 3 - 1").is_game_over() is True
    assert Gungi(NORMAL_FEN).is_game_over() is False


def test_is_draw_integration_cases():
    assert Gungi("m8/9/9/9/9/9/9/9/8M -/- w 3 - 1").is_draw() is True
    assert Gungi(NORMAL_FEN).is_draw() is False
    assert Gungi(CHECKMATE_FEN).is_draw() is False


def test_only_end_draft_moves_generated_with_last_piece():
    gungi = Gungi("9/9/9/9/9/9/9/9/4M4 D1/m1g1i1j2w2n3r2s2f2d4c1a2k1t1 w 3 w 1")
    moves = gungi.moves()

    assert len(moves) > 0
    assert all(move.endswith("\u7d42") for move in moves)


def test_regular_and_end_draft_moves_generated_with_multiple_pieces():
    gungi = Gungi("9/9/9/9/9/9/9/9/4M4 D2/m1g1i1j2w2n3r2s2f2d4c1a2k1t1 w 3 w 1")
    moves = gungi.moves()

    regular_moves = [move for move in moves if not move.endswith("\u7d42")]
    draft_end_moves = [move for move in moves if move.endswith("\u7d42")]

    assert len(regular_moves) > 0
    assert len(draft_end_moves) > 0
