import time
from typing import Optional, List
from maze_core import Cell, Maze
from pathfinding import SearchStrategy

class SearchStats:
    def __init__(self, time_ms: float, visited: int, path_len: int):
        self.time_ms = time_ms
        self.visited_cells = visited
        self.path_length = path_len
    
    def __repr__(self):
        return f"Stats({self.time_ms:.2f}ms, {self.visited_cells} cells, {self.path_length} steps)"

class MazeSolver:
    def __init__(self, maze: Maze, strategy: Optional[SearchStrategy] = None):
        self.maze = maze
        self.strategy = strategy
        self._path = []
        self._observers = []
    
    def set_strategy(self, strategy: SearchStrategy):
        self.strategy = strategy
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def _notify(self, msg: str):
        for obs in self._observers:
            obs.update(msg)
    
    def solve(self) -> SearchStats:
        if not self.strategy:
            raise ValueError("Стратегия не выбрана")
        
        self._notify("Начинаю поиск")
        
        t0 = time.perf_counter()
        path = self.strategy.find_path(self.maze, self.maze.start_cell, self.maze.exit_cell)
        t1 = time.perf_counter()
        
        self._path = path
        ms = (t1 - t0) * 1000
        
        self._notify(f"Найден путь: {len(path)} шагов" if path else "Пути не найдено!")
        
        return SearchStats(ms, self.strategy.visited_count, len(path))
    
    @property
    def last_path(self) -> List[Cell]:
        return self._path