"""
test_tree_value.py
    Test the TreeAndValueMoveSelector class.
    This test compares the trees generated by two different board implementations
    (one with board modification and one without) to ensure they are the same.
    The test uses pytest for parameterized testing and random number generation
    to create the trees.
"""

import random
from importlib.resources import as_file, files
from typing import TYPE_CHECKING

import chess
import pytest

from chipiron.environments.chess_env.board import IBoard, create_board
from chipiron.environments.chess_env.board.utils import FenPlusHistory
from chipiron.players import Player
from chipiron.players.factory import create_chipiron_player
from chipiron.players.move_selector.treevalue import trees
from chipiron.players.move_selector.treevalue.nodes.algorithm_node import AlgorithmNode
from chipiron.players.move_selector.treevalue.tree_and_value_move_selector import (
    TreeAndValueMoveSelector,
)
from chipiron.players.player_ids import PlayerConfigTag
from chipiron.scripts.chipiron_args import ImplementationArgs

if TYPE_CHECKING:
    import chipiron.environments.chess_env.board as boards
    from chipiron.environments import HalfMove
    from chipiron.players.move_selector.treevalue.nodes import ITreeNode
    from chipiron.players.move_selector.treevalue.tree_exploration import (
        TreeExploration,
    )


def create_player_and_tree(
    use_rust_boards: bool, use_board_modification: bool
) -> tuple[Player, trees.MoveAndValueTree]:
    """Helper function to create a player and its corresponding tree."""
    board: IBoard = create_board(
        use_rust_boards=use_rust_boards,
        use_board_modification=use_board_modification,
        sort_legal_moves=True,
        fen_with_history=FenPlusHistory(current_fen=chess.STARTING_FEN),
    )

    random_generator: random.Random = random.Random(0)

    player: Player = create_chipiron_player(
        implementation_args=ImplementationArgs(use_rust_boards=use_rust_boards),
        universal_behavior=True,
        random_generator=random_generator,
    )

    main_move_selector = player.main_move_selector
    assert isinstance(main_move_selector, TreeAndValueMoveSelector)

    tree_exploration: TreeExploration = main_move_selector.create_tree_exploration(
        board=board
    )
    tree: trees.MoveAndValueTree = tree_exploration.explore(
        random_generator=random_generator
    ).tree

    return player, tree


@pytest.mark.parametrize(("use_rust_boards"), (True, False))
def test_random(use_rust_boards: bool) -> None:
    """Test the TreeAndValueMoveSelector class."""
    _, tree_one = create_player_and_tree(use_rust_boards, use_board_modification=False)
    _, tree_two = create_player_and_tree(use_rust_boards, use_board_modification=True)

    half_move: HalfMove
    node_one: ITreeNode
    board_key: boards.boardKey
    node_two: ITreeNode
    for half_move, board_key, node_one in tree_one.descendants.iter_on_all_nodes():
        node_two = tree_two.descendants.descendants_at_half_move[half_move][board_key]
        assert isinstance(node_one, AlgorithmNode)
        assert isinstance(node_two, AlgorithmNode)
        assert node_one.id == node_two.id

    for half_move, board_key, node_two in tree_two.descendants.iter_on_all_nodes():
        node_one = tree_one.descendants.descendants_at_half_move[half_move][board_key]
        assert isinstance(node_one, AlgorithmNode)
        assert isinstance(node_two, AlgorithmNode)
        assert node_one.id == node_two.id


# the list in PlayerConfigTag should correspond to files existing in the data/players/player_config folder
def test_player_config_files_exist() -> None:
    """Test to ensure all player configuration files listed in PlayerConfigTag exist."""
    base_resource = files("chipiron").joinpath("data/players/player_config")

    for tag in PlayerConfigTag:
        if tag is PlayerConfigTag.CHIPIRON:
            resource = base_resource.joinpath("chipiron/chipiron.yaml")
        else:
            resource = base_resource.joinpath(tag.value + ".yaml")

        with as_file(resource) as file_path:
            assert file_path.exists(), f"File does not exist: {file_path}"


if __name__ == "__main__":
    test_player_config_files_exist()
    for use_rusty_board in [True, False]:
        test_random(use_rust_boards=use_rusty_board)
