import heapq
import itertools
from strategies.pathfinding_strategy import PathFindingStrategy


class AStarStrategy(PathFindingStrategy):
    def heuristic(self, cell, exit_cell):
        return abs(cell.x - exit_cell.x) + abs(cell.y - exit_cell.y)

    def find_path(self, maze, start_cell, exit_cell):
        open_set = []
        counter = itertools.count()
        heapq.heappush(open_set, (0, next(counter), start_cell))

        parents = {start_cell: None}
        g_score = {start_cell: 0}
        visited = set()
        visited_count = 0

        while open_set:
            _, _, current = heapq.heappop(open_set)

            if current in visited:
                continue

            visited.add(current)
            visited_count += 1

            if current == exit_cell:
                path = []
                while current is not None:
                    path.append(current)
                    current = parents[current]
                path.reverse()
                return path, visited_count

            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]:
                    parents[neighbor] = current
                    g_score[neighbor] = tentative_g
                    f_score = tentative_g + self.heuristic(neighbor, exit_cell)
                    heapq.heappush(open_set, (f_score, next(counter), neighbor))

        return [], visited_count