<reasoning_content>
The user wants a Python implementation of a priority-based job scheduling queue.
Requirements:
1. `add_job` method accepting `job_id` (str), `data` (dict), and `priority` (int, default=0).
2. Higher priority jobs processed first.
3. FIFO order for same priority.
4. `get_next_job()` method returning `(job_id, data)` or `None`.
5. Priority levels: 0 (Normal), 1 (High), 2 (Critical).
6. Output only Python code.

Implementation details:
- Use `heapq` module for priority queue.
- Since `heapq` is a min-heap, and we want higher priority first, we can store negative priorities or use a max-heap approach. However, `heapq` doesn't support max-heap directly. We can store `(-priority, counter, job_id, data)` where `counter` ensures FIFO for same priorities.
- Alternatively, since priorities are small integers (0, 1, 2), we could use a list of lists, but a heap is more general and efficient.
- Wait, the requirement says "Higher priority jobs should be processed before lower priority jobs". So priority 2 > priority 1 > priority 0.
- Using `heapq`, we store `(-priority, insertion_order, job_id, data)`.
- `insertion_order` can be a simple counter incremented on each `add_job`.
- `get_next_job()` pops from the heap and returns `(job_id, data)`.
- Need to handle the case where the queue is empty.

Let's draft the class:

```python
import heapq

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

    def add_job(self, job_id: str, data: dict, priority: int = 0) -> None:
        # Store as (-priority, counter, job_id, data)
        # Negative priority because heapq is a min-heap
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

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

Check requirements:
1. `add_job` accepts optional priority (default=0) -> Yes.
2. Higher priority processed first -> Yes, `-priority` makes 2 become -2, which is smaller than -1 and 0, so it pops first.
3. Same priority maintains FIFO -> Yes, `self._counter` increases monotonically, so smaller counter pops first.
4. `get_next_job() -> tuple[str, dict] | None` -> Yes.
5. Priority levels example matches -> Yes.
6. Only Python code -> Yes.

One minor thing: `tuple[str, dict] | None` syntax requires Python 3.10+. I'll use it as requested, or standard typing if needed, but the prompt uses it. I'll stick to the prompt's type hint style.

Wait, should I include `import heapq`? Yes.
Should I include type hints? The prompt uses them, so I will.
The prompt says "Write only the Python code, no explanations."

Let's verify 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:
- add normal: (-0, 0, "normal", {...})
- add critical: (-2, 1, "critical", {...})
- add high: (-1, 2, "high", {...})
Heap order: (-2, 1), (-1, 2), (-0, 0) -> pops critical first. Correct.
Next: (-1, 2) -> high. Correct.
Next: (-0, 0) -> normal. Correct.

All good.

One detail: `tuple[str, dict] | None` is valid in Python 3.10+. I'll use it.
I'll make sure the class name is `JobQueue` as implied.
I'll output just the code.

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

class JobQueue:
    def __init__(self) -> None:
        self._queue: list[Tuple[int, int, str, Dict]] = []
        self._counter = 0

    def add_job(self, job_id: str, data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

    def get_next_job(self) -> Optional[Tuple[str, dict]]:
        if not self._queue:
            return None
        _, _, job_id, data = heapq.heappop(self._queue)
        return job_id, data
```

Wait, the prompt uses `tuple[str, dict] | None` syntax. I'll stick to that for consistency, though `Optional` is fine too. I'll just use the exact syntax from the prompt.

Let's refine:
```python
import heapq

class JobQueue:
    def __init__(self) -> None:
        self._queue: list = []
        self._counter = 0

    def add_job(self, job_id: str, data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

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

This matches all requirements. I will output exactly this.
One thing: `tuple[str, dict] | None` might cause a syntax error in Python < 3.10, but the prompt uses it, so it's fine. I'll keep it.
I'll also add `from typing import ...` if needed, but not strictly necessary. I'll just use the built-in types as in the prompt.
The prompt says "Write only the Python code, no explanations."
I will produce the code block.
All checks passed.
Proceed. 
Let's double check the exact prompt: "Modify `add_job` to accept an optional priority parameter (default=0)"
"Add `get_next_job() -> tuple[str, dict] | None` to get the highest priority job"
Everything matches.
Output matches request.
Done. 
I will generate the response now. 
One minor point: `tuple[str, dict] | None` is Python 3.10+ syntax. I'll assume modern Python. If I want to be safe, I could use `Optional[Tuple[str, dict]]`, but the prompt explicitly uses the pipe syntax. I'll stick to the prompt's syntax.
Code looks solid.
Output matches.
Proceeds. 
[Output Generation] -> *Self-Correction/Verification during thought*:
Wait, should I include `import heapq`? Yes.
Should I include type hints? Yes.
Is there any edge case? Empty queue returns None. Correct.
FIFO for same priority? Counter ensures it. Correct.
Higher priority first? Negative priority ensures it in min-heap. Correct.
All good.
Output matches exactly.
```python
import heapq

class JobQueue:
    def __init__(self) -> None:
        self._queue: list = []
        self._counter = 0

    def add_job(self, job_id: str, data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._queue:
            return None
        _, _, job_id, data = heapq.heappop(self._queue)
        return job_id, data
```
This is complete. I will output it. 
Note: I'll make sure formatting is exact. No extra text.
Done. 
Proceeds. 
[Output Generation] -> *Output matches the refined code block.* 
All constraints met. 
Final Check of the Prompt: "Write only the Python code, no explanations." -> I will strictly follow this.
Ready. 
[Output Generation]
```python
import heapq

class JobQueue:
    def __init__(self) -> None:
        self._queue: list = []
        self._counter = 0

    def add_job(self, job_id: str, data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._queue:
            return None
        _, _, job_id, data = heapq.heappop(self._queue)
        return job_id, data
```
Looks good. Output matches.✅
Done. 
(Self-Correction/Note during generation prep: I'll remove the type hints on `self._queue: list = []` to avoid any potential linting warnings, though it's fine. I'll keep it simple.)
Actually, `list` without parameter is fine. I'll stick to the code above.
All good. 
Proceeds. 
[Output Generation] -> *Outputs the code block*
Done. 
[Final Check]
- `add_job` accepts `priority=0`? Yes.
- Higher priority first? Yes (`-priority`).
- Same priority FIFO? Yes (`_counter`).
- `get_next_job` signature matches? Yes.
- Only Python code? Yes.
Ready. 
[Output] -> *Proceeds*

</reasoning_content>

<content>
```python
import heapq

class JobQueue:
    def __init__(self) -> None:
        self._queue: list = []
        self._counter = 0

    def add_job(self, job_id: str, data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

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