<reasoning_content>
Here's a thinking process:

1.  **Understand User Requirements:**
   - Implement a priority-based job scheduling queue.
   - `add_job` should accept an optional `priority` parameter (default=0).
   - Higher priority jobs processed first.
   - Same priority jobs maintain FIFO order.
   - Add `get_next_job() -> tuple[str, dict] | None` to get the highest priority job.
   - Priority levels: 0 (Normal), 1 (High), 2 (Critical) - though the exact levels don't change the logic, just that higher numbers = higher priority.
   - Return only Python code, no explanations.

2.  **Identify Key Data Structures:**
   - Need a way to store jobs with priorities and maintain FIFO within the same priority.
   - Options:
     - `collections.deque` per priority level
     - `heapq` (min-heap) with a counter for FIFO ordering
     - Custom class with sorted insertion
   - `heapq` is efficient and standard for priority queues. To maintain FIFO for same priority, we can use a tuple: `(-priority, insertion_order, job_id, job_data)`. Since `heapq` is a min-heap, negating priority makes higher priority values come out first. The insertion order ensures FIFO for equal priorities.
   - Alternatively, use a dictionary of deques: `self.queues = {0: deque(), 1: deque(), 2: deque()}` and check from highest to lowest. But priorities might be arbitrary, so a heap is more flexible.
   - Let's stick with `heapq` as it's robust and handles arbitrary priorities well.

3.  **Design the Class:**
   ```python
   import heapq
   from collections import deque
   from typing import Optional, Tuple, Dict, Any

   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 so higher priority values are popped first
           # Use counter to maintain FIFO order for same priority
           entry = (-priority, self._counter, job_id, job_data)
           heapq.heappush(self._heap, entry)
           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
   ```

4.  **Check Requirements:**
   - `add_job` accepts optional `priority` parameter (default=0) -> Yes
   - Higher priority jobs processed first -> Yes (using `-priority`)
   - Same priority maintains FIFO -> Yes (using `_counter`)
   - `get_next_job() -> tuple[str, dict] | None` -> Yes
   - Priority levels mentioned are just examples, code handles any int.
   - Return type matches requirement.

   Wait, the requirement says `tuple[str, dict] | None`. In Python 3.10+, `tuple[str, dict] | None` is valid. I'll use standard typing imports or just rely on modern syntax. I'll stick to `from typing import Optional, Tuple, Dict` for compatibility, or just use the exact signature requested. The prompt says `get_next_job() -> tuple[str, dict] | None`, so I'll use that exact signature.

   Let's refine:
   ```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
   ```

   Check edge cases:
   - What if `job_data` contains uncomparable types? `heapq` compares tuples element by element. If `-priority` and `self._counter` are different, it stops there. Since `self._counter` is strictly increasing, ties on priority will never compare `job_id` or `job_data`. So it's safe.
   - The requirement says `tuple[str, dict] | None`. I'll use exactly that.
   - Should I include type hints for `add_job`? The prompt doesn't specify, but it's good practice. I'll keep it simple.
   - The example shows `queue.add_job("normal", {"type": "normal"}, priority=0)`. So parameters are `job_id`, `job_data`, `priority`.
   - All good.

   One minor thing: The prompt says "Write only the Python code, no explanations." I will output just the code block.

   Let's double check the exact signature requested: `get_next_job() -> tuple[str, dict] | None`
   I'll make sure the class matches exactly.

   Code structure:
   ```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
   ```

   Wait, should I consider that `job_data` might be mutated after being popped? The requirement just says return it. It's fine.
   Also, `tuple[str, dict] | None` requires Python 3.10+. That's fine.
   I'll add `from typing import Optional` if needed, but the prompt uses modern syntax. I'll stick to modern syntax.

   One thing: The prompt says "Modify `add_job` to accept an optional priority parameter (default=0)". It implies there might be an existing class, but I'm writing from scratch. I'll just provide the complete class.

   Let's verify FIFO behavior:
   If two jobs have priority 0, they get counters 0 and 1. `(-0, 0, ...)` comes before `(-0, 1, ...)`. So FIFO is maintained. Correct.
   Higher priority first: priority 2 -> `-2`, priority 1 -> `-1`, priority 0 -> `0`. `-2 < -1 < 0`, so `-2` comes out first. Correct.

   All requirements met. I'll output the code.
   I'll make sure it's clean and matches exactly.
   One minor adjustment: I'll add type hints to `add_job` for completeness, but it's not strictly required. I'll keep it simple.
   The prompt says "Write only the Python code, no explanations." So I will output just the code block.

   Final check of the 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 looks solid. I'll output it.✅
   Note: I'll make sure the function signature exactly matches `get_next_job(self) -> tuple[str, dict] | None`.
   All good. 
   Output matches response.✅
   Proceeds. 
   [Self-Correction/Refinement during thought]
   Wait, should I consider that `job_data` might not be hashable/comparable? `heapq` only compares tuples until it finds a difference. Since `_counter` is unique, it will never compare `job_id` or `job_data`. So it's safe.
   The prompt example uses `queue.add_job("normal", {"type": "normal"}, priority=0)`. So parameters are `(job_id, job_data, priority)`.
   I'll stick with this.
   One thing: `tuple[str, dict] | None` is Python 3.10+ syntax. I'll use it as requested.
   Code is ready.✅
   Output matches exactly. 
   Proceeds. 
   [Output Generation] -> *Proceeds*
   ```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
   ```
   Matches all constraints. No extra text. Done. 
   Self-Correction/Verification during generation prep:
   The prompt says "Modify `add_job` to accept an optional priority parameter (default=0)". It doesn't specify the exact signature of `add_job`, but the example shows `queue.add_job("normal", {"type": "normal"}, priority=0)`. So `job_id`, `job_data`, `priority` is correct.
   All good. Output matches. 
   Proceeds. 
   [Output Generation] (matches the final code block)
   *(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>