from gungi.fen import INTRO_POSITION
from gungi.gungi import Gungi
from gungi.pgn import PGNOptions
from gungi.utils import piece


def _first_move() -> str:
    return f"{piece['soldier']}(7-1-1)(6-1-1)"


def _second_move() -> str:
    return f"{piece['warrior']}(3-4-1)(4-4-1)"


def test_set_and_get_comment_for_current_position():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())

    gungi.set_comment("Opening move")
    assert gungi.get_comment() == "Opening move"


def test_get_comment_returns_none_when_missing():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())

    assert gungi.get_comment() is None


def test_remove_comment_returns_removed_comment():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("test")

    assert gungi.remove_comment() == "test"
    assert gungi.get_comment() is None
    assert gungi.remove_comment() is None


def test_get_comments_returns_fen_comment_pairs():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("First move")
    gungi.move(_second_move())
    gungi.set_comment("Second move")

    comments = gungi.get_comments()
    assert len(comments) == 2
    assert any(comment["comment"] == "First move" for comment in comments)
    assert any(comment["comment"] == "Second move" for comment in comments)


def test_remove_comments_clears_all_comments():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("First")
    gungi.move(_second_move())
    gungi.set_comment("Second")

    removed = gungi.remove_comments()
    assert len(removed) == 2
    assert gungi.get_comments() == []


def test_pgn_excludes_comments_by_default():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("test comment")

    pgn = gungi.pgn()
    assert "{" not in pgn
    assert "test comment" not in pgn


def test_pgn_includes_comments_when_requested():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("Opening")
    gungi.move(_second_move())

    pgn = gungi.pgn(PGNOptions(with_comments=True))
    assert "{Opening}" in pgn


def test_reset_clears_comments():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("test")

    gungi.reset()
    assert gungi.get_comments() == []


def test_clear_clears_comments():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("test")

    gungi.clear()
    assert gungi.get_comments() == []


def test_comment_persists_when_returning_to_same_position():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("First position")
    fen = gungi.fen()

    gungi.move(_second_move())
    gungi.undo()

    assert gungi.fen() == fen
    assert gungi.get_comment() == "First position"


def test_load_pgn_parses_comments():
    gungi = Gungi(INTRO_POSITION)
    pgn = f"1. {_first_move()} {{Opening move}} {_second_move()} {{Response}}"

    gungi.load_pgn(pgn, INTRO_POSITION)

    comments = gungi.get_comments()
    assert len(comments) == 2
    assert any(comment["comment"] == "Opening move" for comment in comments)
    assert any(comment["comment"] == "Response" for comment in comments)


def test_pgn_comments_roundtrip():
    gungi = Gungi(INTRO_POSITION)
    gungi.move(_first_move())
    gungi.set_comment("First")
    gungi.move(_second_move())
    gungi.set_comment("Second")

    pgn_with_comments = gungi.pgn(PGNOptions(with_comments=True))

    other = Gungi(INTRO_POSITION)
    other.load_pgn(pgn_with_comments, INTRO_POSITION)

    assert len(other.get_comments()) == 2
    assert other.pgn(PGNOptions(with_comments=True)) == pgn_with_comments
