from queue import PriorityQueue
import math
from graph import Graph


def shortest_path(
    graph: Graph,
    start_node: tuple[int, int],
    end_node: tuple[int, int]
) -> tuple[list[tuple[int, int]], dict[tuple[int, int], float]]:
    """
    Computes the shortest path from node start_node to end_node using
    Dijkstra's algorithm. The path is returned as a list of nodes, as
    well as the distances to all nodes.
    If no such path exist, return the empty list.

    Example / Unit Test:
    >>> g = Graph()
    >>> g.construct_graph("dijkstra_greyscale_map_test.txt")
    >>> path, distances = shortest_path(g, (2, 2), (4, 2))
    >>> path
    [(2, 2), (3, 2), (4, 2)]
    >>> distances[(4,2)]
    4
    >>> path, distances = shortest_path(g, (2, 2), (10, 2))
    >>> path
    []
    >>> distances[(4,2)]
    inf
    >>> path, distances = shortest_path(g, (2, 2), (47, 27))
    >>> distances[(47, 27)]
    179
    """
    distances = {node: math.inf for node in graph.nodes}
    distances[start_node] = 0

    if start_node not in graph.nodes or end_node not in graph.nodes:
        return [], distances

    predecessors = {node: None for node in graph.nodes}

    pq = PriorityQueue()
    pq.put((0, start_node))

    while not pq.empty():
        # TODO implement Dijkstra
        break # delete this break when you start implementing Dijkstra

    if distances[end_node] == math.inf:
        return [], distances

    # TODO reconstruct the path from start_node to end_node using
    path = []
    

    return path, distances
