import heapq
from typing import List, Dict
from .path_finding_strategy import PathFindingStrategy

class AStarStrategy(PathFindingStrategy):
    """A* поиск с эвристикой (манхэттенское расстояние)"""
    
    def __init__(self):
        self._visited_count = 0
    
    @property
    def name(self) -> str:
        return "AStar"
    
    def _heuristic(self, cell, exit_cell) -> int:
        """Манхэттенское расстояние между клетками"""
        return abs(cell.x - exit_cell.x) + abs(cell.y - exit_cell.y)
    
    def find_path(self, maze, start, exit_cell) -> List:
        """Находит путь с помощью A*"""
        if not start or not exit_cell:
            return []
        
        # Приоритетная очередь (F-значение, ID для уникальности, клетка)
        open_set = []
        heapq.heappush(open_set, (0, id(start), start))
        
        # Откуда пришли в каждую клетку
        came_from = {}
        
        # Стоимость пути от старта до клетки (G-значение)
        g_score = {start: 0}
        
        # Оценочная стоимость (F-значение = G + H)
        f_score = {start: self._heuristic(start, exit_cell)}
        
        self._visited_count = 0
        
        while open_set:
            _, _, current = heapq.heappop(open_set)
            self._visited_count += 1
            
            # Нашли выход
            if current == exit_cell:
                return self._reconstruct_path(came_from, exit_cell)
            
            # Проверяем всех соседей
            for neighbor in maze.get_neighbors(current):
                tentative_g = g_score[current] + 1
                
                if neighbor not in g_score or tentative_g < g_score[neighbor]:
                    came_from[neighbor] = current
                    g_score[neighbor] = tentative_g
                    f = tentative_g + self._heuristic(neighbor, exit_cell)
                    f_score[neighbor] = f
                    heapq.heappush(open_set, (f, id(neighbor), neighbor))
        
        # Путь не найден
        return []
    
    def _reconstruct_path(self, came_from: Dict, current) -> List:
        """Восстанавливает путь от старта до exit"""
        path = [current]
        while current in came_from:
            current = came_from[current]
            path.append(current)
        return list(reversed(path))