<reasoning_content>
Here's a thinking process:

1.  **Understand the Goal**: The user wants a Python class implementing a priority-based job scheduler with a queue. It needs specific methods and behavior.

2.  **Key Requirements**:
   - `add_job(job_id: str, job_data: dict, priority: int = 0)`: Add a job with optional priority.
   - Higher priority jobs processed first.
   - Same priority jobs maintain FIFO order.
   - `get_next_job() -> tuple[str, dict] | None`: Return the highest priority job, or None if empty.
   - Priority levels: 0 (Normal, default), 1 (High), 2 (Critical). Higher number = higher priority.
   - Output: Only Python code, no explanations.

3.  **Data Structure Choice**:
   - Need a priority queue that maintains FIFO for same priorities.
   - Python's `heapq` is a min-heap, but we want max-heap behavior for priority (higher number = higher priority). We can negate the priority or use `heapq` with a tuple `( -priority, insertion_order, job_id, job_data )`.
   - Alternatively, use `queue.PriorityQueue` from `queue` module, but it's thread-safe and might be overkill. `heapq` is simpler and more standard for this.
   - Let's use `heapq` with a counter to maintain insertion order for FIFO within same priority.
   - Tuple format for heap: `(-priority, counter, job_id, job_data)`
   - Since higher priority means higher number, negating it makes it a min-heap that picks the highest priority first.
   - Counter ensures FIFO for same priorities.

4.  **Class Design**:
   ```python
   import heapq
   from typing import Optional, Tuple, Dict

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

       def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
           # Use negative priority for max-heap behavior with min-heap heapq
           heapq.heappush(self._heap, (-priority, self._counter, job_id, job_data))
           self._counter += 1

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

5.  **Check Requirements**:
   - `add_job` accepts optional priority parameter (default=0)? Yes.
   - Higher priority jobs processed before lower? Yes, `-priority` ensures higher numbers come first.
   - Same priority maintains FIFO? Yes, `_counter` increases monotonically, so lower counter (earlier added) comes first.
   - `get_next_job() -> tuple[str, dict] | None`? Yes.
   - Priority levels match? The logic handles any integer, but defaults to 0. The example shows 0, 1, 2. Works.
   - Only Python code? Yes.

6.  **Edge Cases & Type Hints**:
   - Use `typing` module for type hints as requested/expected.
   - `Optional[Tuple[str, dict]]` matches `tuple[str, dict] | None` (Python 3.10+ syntax is fine, but I'll stick to standard or use `|` if appropriate. The prompt uses `tuple[str, dict] | None`, so I'll use that or `Optional` for compatibility. I'll use `| None` as it's modern Python, but `Optional` is safer. I'll stick to `| None` or `Optional`. The prompt uses `tuple[str, dict] | None`, so I'll match that.)
   - Actually, Python 3.10+ supports `|`. I'll use `from typing import Optional, Tuple, Dict` and `Optional[Tuple[str, Dict]]` to be safe, or just use the exact syntax from the prompt. I'll use `tuple[str, dict] | None` as requested.
   - Wait, `heapq` expects comparable items. `(-priority, self._counter, job_id, job_data)` works because tuples compare element by element. `job_id` and `job_data` won't be compared unless priorities and counters are equal, which is impossible due to unique counter. So it's safe.
   - Let's verify: `(-2, 0, "c", {...})` vs `(-1, 1, "h", {...})`. `-2 < -1`, so critical comes first. Correct.
   - What about `get_next_job` return type? The prompt says `-> tuple[str, dict] | None`. I'll use that.
   - I'll make sure imports are included.

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

   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)
   ```

   Wait, `tuple[str, dict] | None` syntax requires Python 3.10+. The prompt uses it, so it's fine. I'll stick to it.
   Should I include `from typing import ...`? It's good practice. I'll add it.
   Actually, I can just use `| None` directly if Python 3.10+ is assumed. I'll keep it simple.

   Let's double check the FIFO requirement: "Jobs with the same priority should maintain FIFO order". The counter ensures that. Since `heappush` uses the tuple comparison, and counter is strictly increasing, earlier jobs have smaller counters, so they pop first. Correct.

   One minor thing: `job_data` is a dict. Modifying it later might affect the queue, but that's standard. Not an issue.

   The prompt says "Write only the Python code, no explanations." So I will output exactly the class and necessary imports.

   Final check of the code:
   ```python
   import heapq
   from typing import Optional, Tuple, Dict

   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)
   ```

   Is there any issue with `tuple[str, dict] | None` in older Python? The prompt uses it, so I'll assume 3.10+. I'll keep it.
   Alternatively, I can use `Optional[Tuple[str, dict]]` to be safe, but I'll stick to the prompt's syntax.
   Actually, I'll just use `| None` as requested.

   One thing: `heapq` compares tuples element-wise. If `priority` and `counter` are equal (impossible due to counter), it would compare `job_id` (string) and then `job_data` (dict). Dict comparison raises TypeError in Python 3. But since `counter` is unique, it never reaches `job_id` or `job_data`. So it's safe. To be absolutely robust, I could omit `job_id` and `job_data` from the heap tuple and store them in a separate dict, but that's unnecessary complexity. The current approach is standard and safe.

   I'll output the code exactly as requested.
   Ready.✅
   Output matches the code block.✅
   No extra text.✅
   Proceeds. 
   One minor adjustment: I'll add `from typing import Optional, Tuple, Dict` just in case, but it's not strictly necessary if using `| None`. I'll keep imports minimal.
   Actually, I'll just write the class as is. It's clean.
   Final code:
   ```python
   import heapq

   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 satisfies all requirements. Output matches.✅
   I will generate this. 
   Self-Correction/Refinement during thought: 
   Wait, `tuple[str, dict] | None` is valid in Python 3.10+. The prompt uses it, so it's fine. 
   I'll make sure the type hints match exactly. 
   All good. 
   Output matches the refined code. 
   Proceeds. 
   [Output Generation] -> *Proceeds*
   *(Done.)*

</reasoning_content>

<content>
```python
import heapq

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)
```
</content>