<reasoning_content>
Here's a thinking process:

1.  **Understand the Goal**: The user wants a Python class `JobQueue` that implements priority-based job scheduling. It needs an `add_job` method with an optional priority parameter (default 0), a `get_next_job` method that returns the highest priority job, maintains FIFO for same priorities, and supports priority levels 0 (Normal), 1 (High), 2 (Critical). Higher priority means higher number.

2.  **Key Requirements**:
   - `add_job(name: str, data: dict, priority: int = 0)`
   - Higher priority jobs processed first
   - FIFO for same priority
   - `get_next_job() -> tuple[str, dict] | None`
   - Priority levels: 0, 1, 2 (but should work generally)
   - Return type hint: `tuple[str, dict] | None`
   - Only output Python code, no explanations.

3.  **Data Structure Choice**:
   - Need to maintain order within same priority levels.
   - A priority queue is suitable. Python's `heapq` module implements a min-heap.
   - To use `heapq` for max-heap behavior (higher priority first), I can negate the priority.
   - To maintain FIFO order for same priorities, I can use a counter/timestamp as a secondary sort key. Since `heapq` compares tuples element by element, I can store `( -priority, insertion_order, name, data )`.
   - Wait, `heapq` pops the smallest element. So `-priority` means higher priority (2 becomes -2, 1 becomes -1, 0 becomes 0). -2 < -1 < 0, so -2 pops first. Correct.
   - For FIFO: `insertion_order` starts at 0 and increments. Smaller order pops first. Correct.
   - Alternatively, I could use a list and sort it, but `heapq` is O(log n) for insert and O(log n) for pop, which is better. Or just use a list and `heapq.heappush`/`heapq.heappop`.
   - Actually, since we just need to implement a queue, a simple list with `heapq` is fine. Or even a list of lists (one per priority level) to maintain FIFO naturally without a counter. But `heapq` with a counter is straightforward.
   - Let's stick with `heapq` and a counter for simplicity and robustness.

   Structure: `self.queue = []`, `self.counter = 0`
   Push: `heapq.heappush(self.queue, (-priority, self.counter, name, data))`
   Pop: `priority_neg, order, name, data = heapq.heappop(self.queue)`
   Return: `(name, data)`

4.  **Edge Cases & Details**:
   - `get_next_job()` should return `None` if empty.
   - Type hints: `from typing import Optional, Tuple, Dict` or use modern syntax `tuple[str, dict] | None` as requested.
   - The prompt says `get_next_job() -> tuple[str, dict] | None`. I'll use that.
   - I'll import `heapq` and `typing` if needed, but I can just use built-in types.
   - I'll make sure the class is named `JobQueue` as implied by the example.

   Let's draft it:
   ```python
   import heapq
   from typing import Optional, Tuple, Dict

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

5.  **Check Requirements**:
   - `add_job` accepts optional priority parameter (default=0) -> Yes
   - Higher priority jobs processed before lower -> Yes, negated priority ensures higher numbers pop first
   - FIFO for same priority -> Yes, counter ensures insertion order
   - `get_next_job() -> tuple[str, dict] | None` -> Yes
   - Example matches -> Yes
   - Only Python code -> Yes

   One minor thing: The prompt says `tuple[str, dict] | None`. In Python 3.9+, this is valid. I'll use it directly. I'll avoid `typing` imports unless necessary, but it's fine to include them or just use built-ins. I'll stick to built-ins for simplicity.

   Wait, should I handle the case where `data` might be modified? The prompt doesn't specify, so shallow copy or direct reference is fine. I'll just store as is.

   Let's verify the heap behavior:
   `(-2, 0, "critical", ...)`
   `(-1, 1, "high", ...)`
   `(-0, 2, "normal", ...)`
   Heap pop order: -2, -1, 0. Correct.
   FIFO: counter increases, so smaller counter pops first for same priority. Correct.

   All good.

   One thing: The prompt says `get_next_job() -> tuple[str, dict] | None`. I'll make sure the return type matches exactly.
   I'll write the code cleanly.

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

   class JobQueue:
       def __init__(self) -> None:
           self._queue: list[tuple[int, int, str, dict]] = []
           self._counter: int = 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, `list[tuple[...]]` syntax requires Python 3.9+. The prompt uses `tuple[str, dict] | None`, so Python 3.10+ is assumed. I'll keep it simple without excessive type hints on internal structures to avoid version issues, or just use standard typing. Actually, I'll just use `self._queue = []` and `self._counter = 0` to be safe, or use `typing.List` etc. But it's fine.

   Let's stick to the simplest, most robust version.

   ```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 matches all requirements. I'll output exactly this. No extra text.
   Double check: "Higher priority jobs should be processed before lower priority jobs" -> priority 2 > 1 > 0. My code uses `-priority`, so -2 < -1 < 0, so 2 pops first. Correct.
   "Jobs with the same priority should maintain FIFO order" -> counter ensures this. Correct.
   "Add `get_next_job() -> tuple[str, dict] | None`" -> Correct.
   Only Python code -> Correct.

   One minor point: `tuple[str, dict] | None` is valid in Python 3.10+. I'll keep it as requested.
   I'll wrap it in a clean block.
   Ready.✅
   Output matches response. 
   Self-Correction/Refinement during thought: 
   Should I return a copy of the data dict to prevent external mutation affecting the queue? The prompt doesn't specify, but it's good practice. However, for simplicity and matching typical coding challenge expectations, direct reference is fine. I'll stick to direct reference unless I see a reason not to. The example doesn't show mutation. I'll keep it simple.

   Final 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
   ```
   This is solid. Output matches.✅
   Proceeds. 
   Output Generation. 
   [Done] 
   *Self-Correction/Verification during generation prep*: 
   Wait, the prompt says `get_next_job() -> tuple[str, dict] | None`. In Python 3.9+, `tuple[str, dict]` is valid. I'll assume modern Python. 
   The code is concise and meets all constraints. 
   I will output exactly the code. No markdown? The prompt says "Write only the Python code, no explanations." I'll include markdown code block as is standard, or just raw code. I'll provide raw code inside a code block for safety, but strictly just the code. I'll output just the code block.
   All good. 
   Proceeds. 
   [Output Generation] -> *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>