import os
from maze_core import Maze, Cell
from maze_builder import TextMazeBuilder
from pathfinding import BFSSearch, DFSSearch, AStarSearch
from solver import MazeSolver
from patterns import ConsoleObserver, Player, MoveCommand

def select_maze_file() -> str:
    print("\n Доступные лабиринты:")
    print("1 - small    (10×10, демо)")
    print("2 - medium   (50×50, стандарт)")
    print("3 - large    (100×100, сложный)")
    print("4 - empty    (пустой, тест скорости)")
    print("5 - no_exit  (без выхода, проверка ошибок)")
    
    while True:
        choice = input("\nВыберите номер (1-5): ").strip()
        mapping = {
            '1': 'small.txt', '2': 'medium.txt', '3': 'large.txt',
            '4': 'empty.txt', '5': 'no_exit.txt'
        }
        if choice in mapping:
            return mapping[choice]
        print(" Неверный ввод. Введите число от 1 до 5.")

def draw_maze(maze: Maze, path=None):
    if maze.width > 30 or maze.height > 30:
        return False
    
    path_set = set(path) if path else set()
    print("\n Карта лабиринта:")
    for y in range(maze.height):
        row = []
        for x in range(maze.width):
            cell = maze.cell_at(x, y)
            if cell in path_set:
                if cell.is_start: row.append('S')
                elif cell.is_exit: row.append('E')
                else: row.append('*')
            else:
                row.append(str(cell))
        print(''.join(row))
    return True

def main():
    
    selected_file = select_maze_file()
    maze_path = os.path.join(os.path.dirname(__file__), 'data', selected_file)
    
    try:
        builder = TextMazeBuilder()
        maze = builder.load(maze_path)
        print(f"\nЗагружен: {selected_file} ({maze.width}x{maze.height})")
        
        if not draw_maze(maze):
            print("   (слишком большой для отрисовки в консоли)")
    except FileNotFoundError:
        print(f" Файл {selected_file} не найден в папке data/")
        return
    except Exception as e:
        print(f" Ошибка загрузки: {e}")
        return

    
    solver = MazeSolver(maze)
    view = ConsoleObserver()
    solver.add_observer(view)
    
    strategies = {
        "BFS": BFSSearch(),
        "DFS": DFSSearch(),
        "A*": AStarSearch()
    }
    
    results = []
    for name, strategy in strategies.items():
        solver.set_strategy(strategy)
        print(f"\n🔍 {name}:")
        stats = solver.solve()
        
        print(f"  Время: {stats.time_ms:.3f} мс")
        print(f"  Клеток посещено: {stats.visited_cells}")
        print(f"   Длина пути: {stats.path_length}")
        
        if solver.last_path:
            if not draw_maze(maze, path=solver.last_path):
                print("  (путь не отрисован из-за размера)")
        else:
            print(" Путь не найден!")
            
        results.append((name, stats))

    print(f"{'Алгоритм':<10} {'Время (мс)':<15} {'Посещено':<12} {'Длина':<8}")

    for name, stats in results:
        print(f"{name:<10} {stats.time_ms:<15.3f} {stats.visited_cells:<12} {stats.path_length:<8}")

    # 4. Интерактивный режим (только для маленьких)
    if maze.width <= 30 and maze.height <= 30:
        if input("\n Запустить интерактивный режим? (y/n): ").lower() == 'y':
            interactive_mode(maze)
    else:
        print("\n Для игры запустите программу ещё раз и выберите small.txt")

def interactive_mode(maze: Maze):
    player = Player(maze.start_cell)
    view = ConsoleObserver()
    history = []
    
    while True:
        view.draw(maze, player=player.pos)
        if player.pos == maze.exit_cell:
            print("\n Ура победа! Выход найден!")
            break
        
        move = input("Ход (W/A/S/D, U=отмена, Q=выход): ").upper()
        if move == 'Q': break
        if move == 'U' and history:
            history.pop().undo()
            continue
            
        dirs = {'W': (0,-1), 'S': (0,1), 'A': (-1,0), 'D': (1,0)}
        if move not in dirs: continue
        
        dx, dy = dirs[move]
        new_cell = maze.cell_at(player.pos.x + dx, player.pos.y + dy)
        
        if new_cell and new_cell.passable():
            cmd = MoveCommand(player, new_cell)
            cmd.execute()
            history.append(cmd)
        else:
            print(" Стена! Нельзя пройти.")

if __name__ == "__main__":
    main()