<reasoning_content>
The user wants a Python implementation of a priority-based job scheduler.
Requirements:
1. `add_job` method accepts an optional `priority` parameter (default=0).
2. Higher priority values are processed first.
3. FIFO for same priority.
4. `get_next_job` returns the highest priority job as a tuple `(str, dict)` or `None`.
5. Priority levels: 0 (Normal), 1 (High), 2 (Critical).
6. Only output the Python code.

Implementation details:
- Use a data structure that supports priority queue behavior. `heapq` in Python is suitable.
- Since Python's `heapq` is a min-heap, and we want higher priority first, we can negate the priority or store tuples `(priority, counter, job_name, job_data)`.
- To maintain FIFO for same priority, we need a counter that increments with each `add_job`.
- Tuple comparison in Python compares elements in order. So `(priority, counter, ...)` will sort by priority first (higher first if we negate), then by counter (lower first, which is FIFO).
- Wait, if we use `-priority`, then higher priority becomes more negative, which comes first in min-heap.
- Or we can use `heapq` with `itemgetter` or store `(-priority, counter, job_name, job_data)`.
- Let's define a class `JobQueue`.
- `__init__`: initialize heap and counter.
- `add_job(name, data, priority=0)`: push `(-priority, self.counter, name, data)` to heap, increment counter.
- `get_next_job()`: pop from heap, return `(name, data)`. If heap empty, return `None`.

Let's verify priority levels: 0, 1, 2. Higher is processed first. So 2 > 1 > 0.
Negating: -2 < -1 < 0. Min-heap will pop -2 first. Correct.

Code structure:
```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
        _, _, name, data = heapq.heappop(self._queue)
        return (name, data)
```

Check requirements:
- `add_job` accepts optional priority parameter (default=0) -> Yes.
- Higher priority jobs processed before lower -> Yes, `-priority` ensures higher priority comes first.
- Same priority maintains FIFO -> Yes, `_counter` ensures insertion order.
- `get_next_job() -> tuple[str, dict] | None` -> Yes.
- Priority levels mentioned: 0, 1, 2. The code handles any int, which is fine.
- Only Python code -> Yes.

One minor thing: type hints. The prompt uses `tuple[str, dict] | None`, which is Python 3.10+ syntax. I'll stick to that or use `Optional[Tuple[str, dict]]` if compatibility is a concern, but the prompt uses `|`, so I'll use it. I'll add `from __future__ import annotations` or just rely on Python 3.10+. It's fine.

Wait, should I include imports? Yes.
Should I include the class definition? Yes.

Let's double check the example:
```python
queue = JobQueue()
queue.add_job("normal", {"type": "normal"}, priority=0)
queue.add_job("critical", {"type": "critical"}, priority=2)
queue.add_job("high", {"type": "high"}, priority=1)

job = queue.get_next_job()  # Returns critical job first
```
With my implementation:
push (-0, 0, "normal", ...)
push (-2, 1, "critical", ...)
push (-1, 2, "high", ...)
heap: [(-2, 1, "critical", ...), (-1, 2, "high", ...), (-0, 0, "normal", ...)] (heap order might vary but min is -2)
pop returns (-2, 1, "critical", ...) -> returns ("critical", {"type": "critical"})
Correct.

What about `get_next_job` return type hint? `tuple[str, dict] | None` is fine.
I will write the complete code.

One detail: `heapq` stores tuples. The comparison of tuples in Python compares element by element. If priorities are equal, it compares counters. Since counters are unique and increasing, it will pop the one with the smallest counter first, which is FIFO. This works perfectly.

I'll produce the code now.
No extra text.
Just the code.
Check if any edge cases: empty queue -> returns None. Correct.
Data types: name is str, data is dict. Correct.
I'll add `import heapq` at the top.

Final code:
```python
import heapq
from typing import Optional, Tuple

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
        _, _, name, data = heapq.heappop(self._queue)
        return (name, data)
```
Wait, `Tuple[str, dict] | None` might cause syntax error in older Python, but the prompt uses it, so I'll stick to it or use `Optional[Tuple[str, dict]]`. I'll use `tuple[str, dict] | None` as requested. Actually, `typing` module isn't strictly needed if using built-in generics, but `heapq` is needed. I'll just use the prompt's type hint style.

Let's refine slightly to match exactly:
```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
        _, _, name, data = heapq.heappop(self._queue)
        return (name, data)
```
This looks solid. I will output only this code.
One thing: `tuple[str, dict] | None` is valid in Python 3.10+. I'll assume modern Python.
All requirements met.
Proceed. 
Output matches request.✅
No explanations.
Code block only.
Done. 
Self-Correction/Verification during thought:
Is there any chance `heapq` compares `data` dicts if priorities and counters are equal? Counters are strictly increasing, so they are never equal. So dict comparison won't happen. Safe.
What about `add_job` signature? `def add_job(self, name: str, data: dict, priority: int = 0) -> None:` matches requirement.
`get_next_job` matches.
Priority levels 0,1,2 are just examples, code handles any int.
Everything is correct.
Output matches. 
Proceeds. 
[Output Generation] -> *outputs code*
```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
        _, _, name, data = heapq.heappop(self._queue)
        return (name, data)
```
Matches exactly. No extra text. Ready. 
Note: I'll make sure the formatting is clean. All good. 
Output matches response. 
Proceeds. 
[Done]

</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:
        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>