from __future__ import annotations

import argparse

from maze_solver import (
    AStarStrategy,
    BFSStrategy,
    ConsoleView,
    DFSStrategy,
    DijkstraStrategy,
    Direction,
    MazeSolver,
    MoveCommand,
    Player,
    TextFileMazeBuilder,
)


STRATEGIES = {
    "bfs": BFSStrategy,
    "dfs": DFSStrategy,
    "astar": AStarStrategy,
    "dijkstra": DijkstraStrategy,
}


def main() -> None:
    parser = argparse.ArgumentParser(description="Find a path through a text maze.")
    parser.add_argument("--maze", default="data/mazes/small.txt")
    parser.add_argument(
        "--strategy",
        choices=sorted(STRATEGIES),
        default="astar",
        help="Path-finding algorithm.",
    )
    parser.add_argument("--render", action="store_true", help="Print maze with path.")
    parser.add_argument(
        "--manual",
        action="store_true",
        help="Manual W/A/S/D mode with Z undo and Q quit.",
    )
    args = parser.parse_args()

    maze = TextFileMazeBuilder().build_from_file(args.maze)
    strategy = STRATEGIES[args.strategy]()
    solver = MazeSolver(maze, strategy)
    view = ConsoleView()
    solver.add_observer(view)

    stats = solver.solve()
    print(
        f"Summary: strategy={stats.strategy_name}, time={stats.time_ms:.3f} ms, "
        f"visited={stats.visited_cells}, path_length={stats.path_length}"
    )

    if args.render:
        print(view.render(maze, path=stats.path))

    if args.manual:
        run_manual_mode(maze, view)


def run_manual_mode(maze, view: ConsoleView) -> None:
    player = Player.at_start(maze)
    history: list[MoveCommand] = []

    while True:
        print(view.render(maze, player_position=player.current_cell))
        if player.current_cell == maze.exit:
            print("Exit reached.")
            return

        key = input("Move W/A/S/D, undo Z, quit Q: ").strip().lower()
        if key == "q":
            return
        if key == "z":
            if history:
                history.pop().undo()
            continue

        try:
            command = MoveCommand(player, Direction.from_key(key))
        except ValueError as exc:
            print(exc)
            continue

        if command.execute():
            history.append(command)
        else:
            print("Move blocked.")


if __name__ == "__main__":
    main()
