<reasoning_content>
*   Implement priority-based job scheduling for a `JobQueue` class.
    *   `add_job(name, data, priority=0)`: Add a job with a priority.
    *   Higher priority (higher numbers) comes first.
    *   Same priority follows FIFO (First-In, First-Out).
    *   `get_next_job()`: Returns the highest priority job or `None`.
    *   Priority levels: 0 (Normal), 1 (High), 2 (Critical).

    *   To handle priority efficiently, a Heap (Priority Queue) is standard.
    *   Python's `heapq` module implements a min-heap.
    *   To make it a max-heap for priorities, we can store priorities as negative values (e.g., -2 for priority 2).
    *   To maintain FIFO for same priorities, we need a sequence number (counter).

    *   `self.queue`: A list to store items for `heapq`.
    *   `self.counter`: An integer to track insertion order.

    *   `add_job(name, data, priority=0)`:
        *   Push `(-priority, counter, name, data)` into the heap.
        *   Increment `counter`.

    *   `get_next_job()`:
        *   If heap is empty, return `None`.
        *   Pop the smallest item (which corresponds to highest priority due to negative sign).
        *   Return `(name, data)`.

    *   `heapq` is thread-safe? No, but the prompt doesn't specify thread safety, usually it's single-threaded unless stated.
    *   Input: `queue.add_job("normal", {"type": "normal"}, priority=0)`
    *   Queue state: `[(-0, 0, "normal", {...})]`
    *   Input: `queue.add_job("critical", {"type": "critical"}, priority=2)`
    *   Queue state: `[(-2, 1, "critical", {...}), (-0, 0, "normal", {...})]`
    *   Input: `queue.add_job("high", {"type": "high"}, priority=1)`
    *   Queue state: `[(-2, 1, "critical", {...}), (-1, 2, "high", {...}), (-0, 0, "normal", {...})]`
    *   `get_next_job()`: Pops `(-2, 1, "critical", {...})` -> returns `("critical", {...})`.

    *   Imports: `import heapq`.
    *   Class Definition.
    *   Methods.
</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):
        # Use negative priority to simulate a max-heap using heapq (which is a min-heap)
        # Include counter to maintain FIFO order for identical 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
        
        priority_neg, counter, name, data = heapq.heappop(self.queue)
        return (name, data)
```
</content>