<reasoning_content>
*   Task: Implement priority-based job scheduling in a `JobQueue` class.
    *    Requirements:
        1. `add_job` must accept an optional `priority` parameter (default=0).
        2. Higher priority jobs go first (Priority 2 > 1 > 0).
        3. Same priority jobs should be FIFO (First-In, First-Out).
        4. `get_next_job()` returns the highest priority job or `None`.
    *    Priorities: 0 (Normal), 1 (High), 2 (Critical).
    *    Input: Python code only, no explanations.

    *   Need a data structure to store jobs.
    *   Since it's priority-based and needs to maintain FIFO for equal priorities, a `heapq` (priority queue) is the standard approach.
    *   `heapq` is a min-heap. To make it a max-heap for priority, I can negate the priority value (e.g., Priority 2 becomes -2, Priority 1 becomes -1, Priority 0 becomes 0).
    *   To maintain FIFO for equal priorities, I need a counter to act as a tie-breaker in the heap.

    *   `__init__`: Initialize a list (for the heap) and a counter.
    *   `add_job(name, data, priority=0)`: Push `(-priority, counter, name, data)` into the heap. Increment counter.
    *   `get_next_job()`: Pop from the heap. Return `(name, data)` or `None`.

    *   `heapq.heappush(self._queue, (-priority, self._counter, name, data))`
    *   `self._counter += 1`
    *   `return heapq.heappop(self._queue)[2:]` (unpacking the tuple).

    *   Job 1: "normal", priority 0. Entry: `(0, 0, "normal", {...})`
    *   Job 2: "critical", priority 2. Entry: `(-2, 1, "critical", {...})`
    *   Job 3: "high", priority 1. Entry: `(-1, 2, "high", {...})`
    *   Heap order: `(-2, 1, ...)` then `(-1, 2, ...)` then `(0, 0, ...)`.
    *   Pop result: `("critical", {...})`. Correct.

    *   `JobQueue` class.
    *   `import heapq`.
    *   `add_job` signature: `def add_job(self, name: str, data: dict, priority: int = 0) -> None:`.
    *   `get_next_job` signature: `def get_next_job(self) -> tuple[str, dict] | None:`.

    *   Requirement 1: Done.
    *   Requirement 2: Done (Negated priority in min-heap).
    *   Requirement 3: Done (Counter as tie-breaker).
    *   Requirement 4: Done.

    Wait, is there a simpler way without `heapq`?
    Since there are only 3 priority levels, I could use 3 separate `collections.deque` objects.
    - `self.queues = {0: deque(), 1: deque(), 2: deque()}`
    - `add_job` appends to the specific deque.
    - `get_next_job` looks at `2` then `1` then `0`.

    Both approaches work. `heapq` is more extensible if more priorities are added. `deque` is faster for O(1) appends/pops. The prompt doesn't specify complexity, but `heapq` is the standard way to implement a priority queue. Let's stick to `heapq` or a list-based approach. Actually, for a small fixed set, three deques are very clean. But `heapq` is the classic "Priority Queue" implementation.

    Let's use `heapq` for robustness.

    ```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 -priority because heapq is a min-heap
            # Use self._counter to ensure 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 prompt asks for `tuple[str, dict] | None`. This is Python 3.10+ syntax.

    Let's double check the requirements.
    1. `add_job` optional `priority` (default=0). Check.
    2. Higher priority first. Check (negated value).
    3. Same priority = FIFO. Check (counter).
    4. `get_next_job` return tuple or None. Check.

    Refining the code structure.

    ```python
    import heapq
    from typing import Tuple, Dict, Optional

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

        def add_job(self, name: str, data: dict, priority: int = 0) -> None:
            heapq.heappush(self._queue, (-priority, self._count, name, data))
            self._count += 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)
    ```

    One final check: "Higher priority jobs should be processed before lower priority jobs".
    Priority 2 = Critical.
    Priority 1 = High.
    Priority 0 = Normal.
    Heap stores:
    - `(-2, ...)`
    - `(-1, ...)`
    - `(0, ...)`
    `heappop` gives smallest value first.
    -2 < -1 < 0.
    Correct.

    Code is ready.
</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:
        # Use -priority because heapq is a min-heap, ensuring higher numbers 
        # come out first. The counter ensures FIFO order for equal 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)
```
</content>