from __future__ import annotations

from queue import PriorityQueue
from typing import Generic, TypeVar

T = TypeVar("T")


class PriorityQueueFIFO(Generic[T]):
    """
    Similar to queue.PriorityQueue, except that if two elements have the same
    priority, they are returned in the order they were inserted. Also, the item
    is kept separate from the priority value (with PriorityQueue, the priority
    is part of the item).
    """

    def __init__(self) -> None:
        # Using Tuple instead of tuple because in Python 3.8 and earlier, tuple isn't
        # generic
        self._pq: PriorityQueue[tuple[int, int, T]] = PriorityQueue()
        self._counter: int = 0

    def put(self, priority: int, item: T) -> None:
        """
        Add an item to the queue.

        Parameters
        ----------
        priority
            The priority of the item. Higher priority items will come out of the queue
            before lower priority items.

        item
            The item to put in the queue.
        """
        self._counter += 1
        self._pq.put((-priority, self._counter, item))

    def get(self) -> T:
        iteminfo: tuple[int, int, T] = self._pq.get()
        return iteminfo[2]

    def empty(self) -> bool:
        return self._pq.empty()
