<reasoning_content>
*   Goal: Implement a priority-based job scheduling system.
    *   Requirements:
        1.  `add_job(name, data, priority=0)`: Add a job with a priority.
        2.  Higher priority (larger number) processed first.
        3.  Tie-breaker: FIFO (First-In-First-Out) for same priority.
        4.  `get_next_job() -> tuple[str, dict] | None`: Retrieve and remove the highest priority job.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical).
    *   Output: Python code only.

    *   A standard `heapq` (min-heap) in Python is the most efficient way to handle priorities.
    *   However, `heapq` is a min-heap, meaning the smallest number comes out first.
    *   The requirement states: "Higher priority jobs should be processed before lower priority jobs" (2 > 1 > 0).
    *   To use `heapq` for a max-heap behavior, we can store priorities as negative numbers (e.g., `-priority`).
    *   To handle the FIFO tie-breaker for same priorities in a heap, we need a secondary key: a sequence counter (an incrementing integer). This ensures that if priorities are equal, the one added earlier (smaller counter) comes first.

    *   `self.heap = []`
    *   `self.counter = 0`

    *   `add_job(name, data, priority=0)`:
        *   `heapq.heappush(self.heap, (-priority, self.counter, name, data))`
        *   `self.counter += 1`

    *   `get_next_job()`:
        *   If not heap, return `None`.
        *   `neg_prio, count, name, data = heapq.heappop(self.heap)`
        *   Return `(name, data)`

    *   `add_job("normal", {}, 0)` -> heap: `[(0, 0, "normal", {})]`
    *   `add_job("critical", {}, 2)` -> heap: `[(-2, 1, "critical", {}), (0, 0, "normal", {})]`
    *   `add_job("high", {}, 1)` -> heap: `[(-2, 1, "critical", {}), (0, 0, "normal", {}), (-1, 2, "high", {})]` (Wait, the order in heap is different, but `heappop` will return `-2` first).
    *   Wait, the counter logic:
        1. `(-0, 0, "normal", {})`
        2. `(-2, 1, "critical", {})`
        3. `(-1, 2, "high", {})`
        Pop 1: `(-2, 1, "critical", {})` -> returns `("critical", {})`. Correct.
        Pop 2: `(-1, 2, "high", {})` -> returns `("high", {})`. Correct.
        Pop 3: `(0, 0, "normal", {})` -> returns `("normal", {})`. Correct.

    *   What if priorities are same?
        1. `(-1, 0, "job1", {})`
        2. `(-1, 1, "job2", {})`
        Pop 1: `(-1, 0, "job1", {})`. Correct (FIFO).

    *   `import heapq`
    *   `class JobQueue:`
    *   `def __init__(self): ...`
    *   `def add_job(self, name, data, priority=0): ...`
    *   `def get_next_job(self): ...`

    *   Python 3.10+ type hinting for return type: `tuple[str, dict] | None`.

    *   `add_job` accepts `priority=0`.
    *   Higher priority first.
    *   Same priority -> FIFO.
    *   `get_next_job` returns the tuple.

    *Self-Correction on Priority*: Since the requirement says `priority=2` is Critical and `priority=0` is Normal, we want `2` to come out before `0`. In a min-heap, we store `-2` and `0`. `-2` is smaller than `0`, so `-2` comes out first. This is correct.

    ```python
    import heapq

    class JobQueue:
        def __init__(self):
            self._queue = []
            self._counter = 0

        def add_job(self, name: str, data: dict, priority: int = 0) -> None:
            # Use negative priority for max-heap behavior
            # Use self._counter to ensure FIFO for same priorities
            heapq.heappush(self._queue, (-priority, self._counter, name, data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            _, _, name, data = heapq.heappop(self._queue)
            return name, data
    ```

    *Wait*, the requirement for `get_next_job` return type is `tuple[str, dict] | None`. My code returns `name, data` which is a tuple.

    *Check constraints*: "Write only the Python code, no explanations."

    *Final refinement*: Make sure the imports and class definition are clean.

    ```python
    import heapq

    class JobQueue:
        def __init__(self):
            self._queue = []
            self._counter = 0

        def add_job(self, name: str, data: dict, priority: int = 0) -> None:
            heapq.heappush(self._queue, (-priority, self._counter, name, data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            priority_neg, count, name, data = heapq.heappop(self._queue)
            return name, data
    ```

    Wait, one edge case: if someone passes a very large priority? It doesn't matter, the heap handles it. If someone passes a negative priority? Requirement doesn't specify, but standard behavior applies. The priority levels given are 0, 1, 2.

    One more check on FIFO:
    `add_job("a", {}, 1)` -> `heap: [(-1, 0, "a", {})]`
    `add_job("b", {}, 1)` -> `heap: [(-1, 0, "a", {}), (-1, 1, "b", {})]`
    `heappop` will pick `(-1, 0, ...)` because `0 < 1`. This is correct.

    Implementation looks solid.
</reasoning_content>

<content>
```python
import heapq

class JobQueue:
    def __init__(self):
        self._queue = []
        self._counter = 0

    def add_job(self, name: str, data: dict, priority: int = 0) -> None:
        """
        Adds a job to the queue. 
        Uses negative priority for max-heap behavior and a counter for FIFO.
        """
        # heapq is a min-heap. By negating priority, the highest number 
        # becomes the smallest number, ensuring it is processed first.
        # The counter ensures that jobs with the same priority maintain FIFO order.
        heapq.heappush(self._queue, (-priority, self._counter, name, data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        """
        Retrieves and removes the highest priority job from the queue.
        Returns None if the queue is empty.
        """
        if not self._queue:
            return None
        
        _, _, name, data = heapq.heappop(self._queue)
        return name, data
```
</content>