<reasoning_content>
*   Goal: Implement priority-based job scheduling for a queue.
    *   Requirement 1: Modify `add_job` to accept `priority` (default=0).
    *   Requirement 2: Higher priority first.
    *   Requirement 3: Same priority must be FIFO (First-In-First-Out).
    *   Requirement 4: Add `get_next_job()` returning `tuple[str, dict]` or `None`.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical).
    *   Constraint: Write only Python code, no explanations.

    *   To handle priorities efficiently, a Max-Heap is usually the best choice. However, standard Python `heapq` is a Min-Heap.
    *   To turn a Min-Heap into a Max-Heap, we can negate the priority values.
    *   To maintain FIFO for identical priorities in a heap, we need a secondary tie-breaker (a counter).
    *   Data structure: `heapq` module.

    *   `JobQueue` class.
    *   `__init__`: Initialize a list (heap) and a counter.
    *   `add_job(name, data, priority=0)`:
        *   Push `(-priority, counter, name, data)` into the heap.
    *   `get_next_job()`:
        *   Pop from heap and return `(name, data)`.

    *   `import heapq`
    *   `counter = 0`
    *   `heap = []`
    *   `add_job(name, data, priority=0)`:
        *   `heapq.heappush(heap, (-priority, counter, name, data))`
        *   `counter += 1`
    *   `get_next_job()`:
        *   If heap empty, return None.
        *   Pop `(-priority, counter, name, data)`.
        *   Return `(name, data)`.

    *   Requirement 1: `priority=0` included.
    *   Requirement 2: Higher priority first (handled by negation `-priority` in min-heap).
    *   Requirement 3: FIFO for same priority (handled by `counter`).
    *   Requirement 4: `get_next_job()` signature matches.

    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Using -priority because heapq is a min-heap,
            # and we want higher priority numbers to come out first.
            # counter ensures FIFO for same priority.
            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 example shows `priority=2` being "Critical".
    In a min-heap, -2 is smaller than -1. So -2 comes out first. Correct.
    If `priority=1` and `priority=1`, the counter `counter` ensures the one added first comes out first. Correct.

    Let's double check the return type hint. `tuple[str, dict] | None`.

    Final check on logic:
    `add_job("normal", ..., priority=0)` -> `(0, 0, "normal", ...)`
    `add_job("critical", ..., priority=2)` -> `(-2, 1, "critical", ...)`
    `add_job("high", ..., priority=1)` -> `(-1, 2, "high", ...)`
    Heap state: `[(-2, 1, ...), (-1, 2, ...), (0, 0, ...)]`
    `heappop` -> `(-2, 1, "critical", ...)`
    Matches requirements.
</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):
        # heapq is a min-heap. By negating the priority, 
        # higher priority numbers will be treated as smaller values.
        # The counter ensures FIFO order for jobs with the same priority.
        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)
```
</content>