<reasoning_content>
*   Goal: Implement priority-based job scheduling.
    *   Input: `add_job` needs a `priority` parameter (default=0).
    *   Ordering: Higher priority first. If priorities are equal, maintain FIFO (First-In, First-Out).
    *   Method `get_next_job()` returns `tuple[str, dict]` or `None`.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical).
    *   Implementation Detail: A priority queue usually uses a heap. Since it's a min-heap and we want higher numbers to come first, we can store priority as a negative value or use a custom comparison. However, the simplest way to handle FIFO with priority in a heap is to store a sequence number (counter) alongside the priority.

    *   Use `heapq`.
    *   Store jobs as tuples: `(-priority, counter, name, data)`.
    *   `counter` ensures FIFO for same priorities.
    *   `priority` is negated because `heapq` is a min-heap (lowest value comes out first, we want highest priority).

    *   `__init__`: Initialize `self.jobs = []` and `self.counter = 0`.
    *   `add_job(self, name: str, data: dict, priority: int = 0)`:
        *   Push `(-priority, self.counter, name, data)` into `self.jobs`.
        *   Increment `self.counter`.
    *   `get_next_job(self) -> tuple[str, dict] | None`:
        *   If empty, return `None`.
        *   Pop the smallest tuple from heap.
        *   Return `(name, data)`.

    *   Requirement 1: `add_job` accepts `priority` (default=0). Yes.
    *   Requirement 2: Higher priority first. Yes, using negated priority in min-heap.
    *   Requirement 3: Same priority = FIFO. Yes, using a monotonic counter.
    *   Requirement 4: `get_next_job` signature and return value. Yes.

    ```python
    import heapq

    class JobQueue:
        def __init__(self):
            self.jobs = []
            self.counter = 0

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Use -priority because heapq is a min-heap
            # counter ensures FIFO for same priority
            heapq.heappush(self.jobs, (-priority, self.counter, name, data))
            self.counter += 1

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

    Wait, the requirement says:
    `queue.add_job("normal", {"type": "normal"}, priority=0)`
    `queue.add_job("critical", {"type": "critical"}, priority=2)`
    `queue.add_job("high", {"type": "high"}, priority=1)`
    `queue.get_next_job()` -> `("critical", {"type": "critical"})`

    My logic:
    - `(-0, 0, "normal", ...)`
    - `(-2, 1, "critical", ...)`
    - `(-1, 2, "high", ...)`
    Heap pops smallest first: `-2` < `-1` < `0`. Correct.

    Check `None` return type.
    `tuple[str, dict] | None` requires `from __future__ import annotations` or just Python 3.10+ syntax. I'll stick to standard type hinting style.

    One detail: `priority` levels are 0, 1, 2.
    Highest priority = 2.
    Lowest priority = 0.
    Min-heap sorts lowest number first.
    So `-2` comes before `-1`. Correct.
</reasoning_content>

<content>
```python
import heapq
from typing import tuple, dict, Optional

class JobQueue:
    def __init__(self):
        self.jobs = []
        self.counter = 0

    def add_job(self, name: str, data: dict, priority: int = 0):
        # Use negative priority because heapq is a min-heap (smallest value first).
        # Counter ensures FIFO order for jobs with the same priority.
        heapq.heappush(self.jobs, (-priority, self.counter, name, data))
        self.counter += 1

    def get_next_job(self) -> Optional[tuple[str, dict]]:
        if not self.jobs:
            return None
        
        _, _, name, data = heapq.heappop(self.jobs)
        return (name, data)
```
</content>