from abc import ABC, abstractmethod
from typing import List, Optional
from models import Cell, Maze


class Observer(ABC):
    """Абстрактный наблюдатель"""
    
    @abstractmethod
    def update(self, event: str, data: dict) -> None:
        """Обработка события"""
        pass


class ConsoleView(Observer):
    """Консольная визуализация лабиринта"""
    
    def render(self, maze: Maze, player_position: Optional[Cell] = None, 
               path: Optional[List[Cell]] = None) -> None:
        """Отрисовывает лабиринт в консоли"""
        path_set = set(path) if path else set()
        
        print("\n+" + "-" * maze.width + "+")
        
        for y in range(maze.height):
            row = []
            for x in range(maze.width):
                cell = maze.get_cell(x, y)
                if cell is None:
                    row.append('?')
                elif player_position and cell == player_position:
                    row.append('@')
                elif cell.is_start:
                    row.append('S')
                elif cell.is_exit:
                    row.append('E')
                elif cell in path_set:
                    row.append('*')
                elif cell.is_wall:
                    row.append('#')
                else:
                    row.append(' ')
            print("|" + ''.join(row) + "|")
        
        print("+" + "-" * maze.width + "+")
    
    def update(self, event: str, data: dict) -> None:
        """Обработка событий от MazeSolver"""
        if event == "maze_loaded":
            maze = data.get('maze')
            print("\n📦 Лабиринт загружен:")
            self.render(maze)
        
        elif event == "search_start":
            algorithm = data.get('algorithm', 'Unknown')
            print(f"\n🔍 Начинаем поиск алгоритмом: {algorithm}")
        
        elif event == "path_found":
            maze = data.get('maze')
            path = data.get('path')
            stats = data.get('stats')
            print(f"\n✅ Путь найден! {stats}")
            self.render(maze, path=path)
        
        elif event == "no_path":
            stats = data.get('stats')
            print(f"\n❌ {stats}")
        
        elif event == "player_moved":
            maze = data.get('maze')
            player = data.get('player')
            if player:
                self.render(maze, player_position=player.current_cell)