<reasoning_content>
Here's a thinking process:

1.  **Understand the Goal**: The user wants a Python implementation of a priority-based job scheduling queue. The queue needs to support adding jobs with priorities, retrieving the highest priority job next, and maintaining FIFO order for jobs with the same priority.

2.  **Key Requirements**:
   - `add_job(job_id: str, job_data: dict, priority: int = 0)`: Add a job with optional priority.
   - Higher priority = processed first.
   - Same priority = FIFO order.
   - `get_next_job() -> tuple[str, dict] | None`: Return the highest priority job's (job_id, job_data) or None if empty.
   - Priority levels: 0 (Normal), 1 (High), 2 (Critical). Note: The requirement says "Higher priority jobs should be processed before lower priority jobs", and the example shows priority=2 being processed before priority=0. So higher number = higher priority.
   - Output: Only Python code, no explanations.

3.  **Data Structure Choice**:
   - To support priority + FIFO, a common approach is to use a priority queue (heap) or a sorted list.
   - Python's `heapq` module provides a min-heap. Since we want higher numbers to be processed first, we can negate the priority in the heap, or use a max-heap approach. Alternatively, we can use `heapq` with tuples: `(-priority, insertion_order, job_id, job_data)`.
   - Using an insertion counter ensures FIFO for same priorities. Since `heapq` compares tuples element by element, `(-priority, counter, job_id, job_data)` will work perfectly. Lower `-priority` means higher priority. Counter ensures FIFO.
   - Wait, `heapq` is a min-heap. So `(-priority, counter, ...)` will pop the smallest `-priority` first, which corresponds to the largest `priority`. The counter ensures that for the same priority, smaller counter (earlier insertion) comes first. This matches FIFO.
   - Alternatively, use `collections.deque` for each priority level? But priorities are just 0, 1, 2 in the example, but the requirement says "optional priority parameter", implying it could be any integer. The heap approach is more general and efficient.
   - Let's stick with `heapq`.

4.  **Implementation Details**:
   - Need a class `JobQueue`.
   - Initialize with `self._queue = []` and `self._counter = 0`.
   - `add_job(self, job_id: str, job_data: dict, priority: int = 0)`:
     - Push to heap: `heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))`
     - Increment counter: `self._counter += 1`
   - `get_next_job(self) -> tuple[str, dict] | None`:
     - Check if empty: `if not self._queue: return None`
     - Pop: `_, _, job_id, job_data = heapq.heappop(self._queue)`
     - Return: `return (job_id, job_data)`
   - Type hints: Use `typing` or built-in `tuple[str, dict] | None` (Python 3.10+). The prompt uses `tuple[str, dict] | None`, so I'll assume Python 3.10+ or just use `Optional[Tuple[str, dict]]` for broader compatibility, but I'll stick to the prompt's style. I'll use `from typing import Optional, Tuple` to be safe, or just use the modern syntax if it's fine. I'll stick to modern syntax as requested, or just standard typing. Actually, I'll just write it cleanly.

   Let's draft it:
   ```python
   import heapq

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

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

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

5.  **Check Requirements**:
   - `add_job` accepts optional priority (default=0) -> Yes.
   - Higher priority processed first -> Yes, using `-priority` in min-heap.
   - Same priority maintains FIFO -> Yes, using `_counter`.
   - `get_next_job() -> tuple[str, dict] | None` -> Yes.
   - Priority levels mentioned (0, 1, 2) are just examples, the implementation handles any integer priority correctly.
   - Only Python code, no explanations -> Will output just the code block.

   One minor point: The prompt says `get_next_job() -> tuple[str, dict] | None`. In Python < 3.10, this syntax isn't valid without `from __future__ import annotations` or `typing.Union`. I'll use `Optional[Tuple[str, dict]]` or just stick to the prompt's syntax assuming modern Python. I'll use `from typing import Optional, Tuple` to be safe, or just keep the prompt's syntax. Actually, many platforms support 3.10+. I'll just use the exact signature requested.

   Let's verify the heap behavior:
   `heapq` is a min-heap.
   Push: `(-priority, counter, job_id, job_data)`
   If priority=2, counter=0 -> `(-2, 0, ...)`
   If priority=1, counter=1 -> `(-1, 1, ...)`
   If priority=0, counter=2 -> `(0, 2, ...)`
   Min-heap pops smallest first: `-2` < `-1` < `0`. So priority 2 pops first. Correct.
   Same priority: `(-1, 0, ...)` vs `(-1, 1, ...)` -> pops counter 0 first. FIFO. Correct.

   All good.

   I'll write the complete class. I'll add `import heapq` at the top.
   I'll make sure the type hints match the prompt.
   I'll avoid any extra text.

   Code:
   ```python
   import heapq
   from typing import Optional, Tuple

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

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

       def get_next_job(self) -> Tuple[str, dict] | None:
           if not self._queue:
               return None
           _, _, job_id, job_data = heapq.heappop(self._queue)
           return job_id, job_data
   ```
   Wait, `Tuple[str, dict] | None` is valid in 3.10+. I'll just use `Optional[Tuple[str, dict]]` to be strictly compatible, or stick to the prompt. The prompt uses `tuple[str, dict] | None`, so I'll use exactly that. Python 3.10 is standard now.

   One thing: `job_data` is a dict. In Python, `dict` is fine.
   I'll keep it simple.

   Final check of the prompt: "Write only the Python code, no explanations."
   I will output just the code block.

   Let's produce it. 
   Self-Correction/Refinement during thought: 
   Should I handle the case where `job_data` might be mutated? Not required.
   Should I use `typing` imports? I'll include them for safety, but the prompt's signature doesn't use them. I'll just match the prompt's signature exactly.
   I'll write:
   ```python
   import heapq
   from typing import Optional, Tuple

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

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

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._heap:
               return None
           _, _, job_id, job_data = heapq.heappop(self._heap)
           return job_id, job_data
   ```
   This matches all requirements. I'll output exactly this. No extra text.
   One minor point: `tuple[str, dict] | None` might cause a syntax error in older Python versions, but it's standard in 3.10+. I'll keep it as requested.
   All good.✅
   Output matches response. 
   Proceeds. 
   [Output Generation] -> *Proceeds*
   *(Self-Correction/Verification during generation prep)*: 
   Wait, `heapq` compares tuples element-wise. If `job_id` or `job_data` are compared (which shouldn't happen due to counter), it could fail. But since `counter` is strictly increasing and unique, the tuple comparison will never reach `job_id` or `job_data`. So it's safe.
   The code is solid.
   I will output it now. 
   Output matches the final code block.✅
   [Done]
   *Output Generation* (matches the final code)
   ```python
   import heapq
   from typing import Optional, Tuple

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

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

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._queue:
               return None
           _, _, job_id, job_data = heapq.heappop(self._queue)
           return job_id, job_data
   ```
   Actually, I'll remove the `typing` imports to keep it clean and match the prompt's exact signature style, as `tuple[...] | None` is valid in modern Python. I'll just stick to the prompt.
   Final code:
   ```python
   import heapq

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

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

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._queue:
               return None
           _, _, job_id, job_data = heapq.heappop(self._queue)
           return job_id, job_data
   ```
   This is perfect. Output matches.✅
   Proceeds. 
   [Output Generation] -> *Outputs exactly the code block* (as requested)
   *(Done.)*

</reasoning_content>

<content>
```python
import heapq

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

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

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