"""
Главный файл запуска — интерактивное меню.

Запуск: python main.py
"""

import os

from maze_builder import TextFileMazeBuilder
from maze_solver import MazeSolver
from strategies import BFSStrategy, DFSStrategy, AStarStrategy, DijkstraStrategy
from observer import ConsoleView
from command import Player, MoveCommand

STRATEGIES = {
    "1": ("BFS",      BFSStrategy),
    "2": ("DFS",      DFSStrategy),
    "3": ("A*",       AStarStrategy),
    "4": ("Dijkstra", DijkstraStrategy),
}

DIRECTION_MAP = {
    "w": (0, -1),
    "s": (0,  1),
    "a": (-1, 0),
    "d": (1,  0),
}


def choose_strategy():
    print("\nВыберите алгоритм:")
    for key, (name, _) in STRATEGIES.items():
        print(f"  {key}. {name}")
    choice = input("Ваш выбор: ").strip()
    if choice not in STRATEGIES:
        print("Неверный выбор, используется BFS.")
        return BFSStrategy()
    name, cls = STRATEGIES[choice]
    print(f"Выбран: {name}")
    return cls()


def interactive_walk(maze, path):
    """Пошаговое ручное перемещение игрока по лабиринту (паттерн Command)."""
    player = Player(maze.start)
    view = ConsoleView()
    history: list[MoveCommand] = []

    print("\n=== Ручное управление ===")
    print("W/A/S/D — движение, U — отмена, Q — выход")
    view.render(maze, path=path, player=player.current_cell)

    while True:
        cmd_input = input("Ход: ").strip().lower()

        if cmd_input == "q":
            break

        if cmd_input == "u":
            if history:
                history.pop().undo()
                view.render(maze, path=path, player=player.current_cell)
            else:
                print("Нет ходов для отмены.")
            continue

        if cmd_input in DIRECTION_MAP:
            dx, dy = DIRECTION_MAP[cmd_input]
            nx, ny = player.current_cell.x + dx, player.current_cell.y + dy
            if 0 <= nx < maze.width and 0 <= ny < maze.height:
                target = maze.get_cell(nx, ny)
                cmd = MoveCommand(player, target, maze)
                cmd.execute()
                history.append(cmd)
                view.render(maze, path=path, player=player.current_cell)
                if player.current_cell == maze.exit:
                    print("🎉 Вы достигли выхода!")
                    break
            else:
                print("За пределами лабиринта.")
        else:
            print("Неизвестная команда.")


def main():
    print("╔══════════════════════════════╗")
    print("║    Решатель лабиринтов       ║")
    print("╚══════════════════════════════╝")

    # Выбор файла
    mazes_dir = "mazes"
    if os.path.isdir(mazes_dir):
        files = [f for f in sorted(os.listdir(mazes_dir)) if f.endswith(".txt")]
        if files:
            print("\nДоступные лабиринты:")
            for i, f in enumerate(files, 1):
                print(f"  {i}. {f}")
            choice = input("Выберите номер (или введите путь): ").strip()
            if choice.isdigit() and 1 <= int(choice) <= len(files):
                maze_path = os.path.join(mazes_dir, files[int(choice) - 1])
            else:
                maze_path = choice
        else:
            maze_path = input("Путь к файлу лабиринта: ").strip()
    else:
        maze_path = input("Путь к файлу лабиринта: ").strip()

    # Загрузка
    builder = TextFileMazeBuilder()
    try:
        maze = builder.build_from_file(maze_path)
        print(f"\nЛабиринт загружен: {maze.width}×{maze.height}")
    except (FileNotFoundError, ValueError) as e:
        print(f"Ошибка: {e}")
        return

    # Выбор стратегии и решение
    strategy = choose_strategy()
    view = ConsoleView()

    solver = MazeSolver(maze, strategy)
    solver.add_observer(view)
    stats = solver.solve()

    print(f"\n── Статистика ──────────────────")
    print(f"  Время:           {stats.time_ms:.4f} мс")
    print(f"  Посещено клеток: {stats.visited_cells}")
    print(f"  Длина пути:      {stats.path_length}")

    # Предложить ручное управление
    if stats.path:
        walk = input("\nЗапустить ручное управление? (y/n): ").strip().lower()
        if walk == "y":
            interactive_walk(maze, stats.path)


if __name__ == "__main__":
    main()
