<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 to support adding jobs with optional priority (default 0), higher priority processed first, FIFO for same priority, and a `get_next_job()` method that returns a tuple of (job_id, job_data) or None.

2.  **Identify Key Requirements**:
   - `add_job(job_id: str, job_data: dict, priority: int = 0)`
   - Higher priority number = higher priority (2 > 1 > 0)
   - Same priority maintains FIFO order
   - `get_next_job() -> tuple[str, dict] | None`
   - Return type hints as specified
   - Only output Python code, no explanations

3.  **Choose Data Structure**:
   - Need a priority queue that supports:
     - Higher priority first
     - FIFO for same priority
   - Python's `heapq` module implements a min-heap. To get higher priority first, I can negate the priority value.
   - To maintain FIFO order for same priority, I can use a counter/timestamp as a secondary sort key.
   - Heap item format: `(-priority, counter, job_id, job_data)`
   - `heapq.heappush` and `heapq.heappop` will handle ordering correctly.

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

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

       def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
           # Negate priority so higher priority comes first in min-heap
           heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
           self._counter += 1

       def get_next_job(self) -> Optional[Tuple[str, dict]]:
           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 parameter (default=0)? Yes.
   - Higher priority jobs processed before lower? Yes, negated priority in min-heap.
   - Same priority maintains FIFO? Yes, counter ensures insertion order.
   - `get_next_job() -> tuple[str, dict] | None`? Yes, matches signature.
   - Example works? Let's trace:
     - add "normal", priority 0 -> heap: `[(0, 0, "normal", {...})]`
     - add "critical", priority 2 -> heap: `[(-2, 1, "critical", {...}), (0, 0, "normal", {...})]`
     - add "high", priority 1 -> heap: `[(-2, 1, "critical", {...}), (0, 0, "normal", {...}), (-1, 2, "high", {...})]` (heapq maintains heap property)
     - get_next_job -> pops `(-2, 1, "critical", {...})` -> returns `("critical", {...})`. Correct.
   - Type hints match? `tuple[str, dict] | None` is Python 3.10+ syntax. I'll use `from typing import Optional, Tuple, Dict` and `Optional[Tuple[str, dict]]` or keep the union syntax if preferred. The prompt uses `tuple[str, dict] | None`, which is fine in modern Python. I'll stick to standard typing or just use the union syntax directly. I'll use `from typing import Optional, Tuple, Dict` for compatibility, or just use `tuple[str, dict] | None` directly since it's valid in 3.10+. I'll keep it simple.

   Wait, the prompt says `get_next_job() -> tuple[str, dict] | None`. I'll use exactly that.

   Let's refine the code to match exactly:
   ```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)
   ```

6.  **Edge Cases & Considerations**:
   - What if `job_id` or `job_data` contains uncomparable types? Not an issue here since we're using priority and counter as primary/secondary keys, and heapq stops comparing once it finds a difference. The counter ensures strict ordering.
   - Type hints: `tuple[str, dict] | None` requires Python 3.10+. I'll assume it's fine as per prompt. Alternatively, I can use `Optional[Tuple[str, dict]]` to be safe, but I'll stick to the prompt's syntax.
   - The prompt says "Write only the Python code, no explanations."
   - I should ensure imports are included.
   - I'll add `__init__` to initialize the queue.
   - I'll make sure the class name is `JobQueue` as implied by the example.

   One minor thing: `heapq` compares tuples element by element. Since `-priority` and `self._counter` are both integers, it's fine. If `job_id` or `job_data` were compared, they might cause TypeError, but they won't be because the first two elements are always different (counter is unique). So it's safe.

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

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

   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, should I use `typing` module or built-in types? The prompt uses `tuple[str, dict] | None`, which is built-in in 3.10+. I'll just use it directly. I'll also add `from typing import Optional, Tuple, Dict` if needed, but it's not strictly necessary. I'll keep it minimal.

   Let's verify the example works:
   ```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
   ```
   This matches perfectly.

   One thing: `job_data` is passed as `dict`, but in Python, it's better to use `dict` type hint. The prompt says `dict`. I'll stick with it.

   Final check of the code:
   - Imports: `import heapq`
   - Class: `JobQueue`
   - `__init__`: initializes heap and counter
   - `add_job`: pushes to heap with negated priority and counter
   - `get_next_job`: pops from heap, returns tuple or None
   - Type hints match prompt
   - No extra text

   All good. I'll output exactly the code.
   One minor adjustment: I'll add `from typing import Optional, Tuple, Dict` just to be safe with older Python versions if needed, but the prompt uses union syntax. I'll stick to the prompt's syntax. Actually, `tuple[str, dict] | None` is fine. I'll just write the code as requested.

   I will produce exactly the code block.
   ```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.✅
   Wait, should I include type hints for `add_job`? The prompt doesn't specify, but it's good practice. I'll add them.
   The prompt says: `Modify add_job to accept an optional priority parameter (default=0)`
   I'll keep the signature as `def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:`
   All good.
   Output matches request.✅
   Proceeds. 
   One detail: `tuple[str, dict] | None` requires Python 3.10+. If the environment is older, it might fail. But the prompt explicitly uses that syntax, so I'll use it. I'll also add `from __future__ import annotations` or just rely on modern Python. I'll stick to the prompt's syntax.
   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)
   ```
   Looks ready. Output matches exactly.✅
   I will generate it now. 
   Self-Correction/Verification during thought: 
   Is there any chance `job_data` could be mutated and affect the heap? No, it's just stored. 
   Is `self._counter` guaranteed to be unique? Yes, it increments each time. 
   Does heapq handle tuples correctly? Yes, compares element by element. 
   The prompt says `tuple[str, dict] | None`, I'll use exactly that. 
   All requirements met. 
   Output matches. 
   Proceeds. 
   [Output Generation] -> *Proceeds*
   *(Note: I'll make sure to include the exact class structure requested without extra fluff.)*
   Final check of the prompt: "Write only the Python code, no explanations."
   I will output just the code block.✅
   Done. 
   [Output] -> *Code Block*
   ```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 matches all constraints. Ready. 
   *Self-Correction/Refinement during thought*: 
   Wait, `tuple[str, dict] | None` is valid in Python 3.10+. To be strictly compatible with the prompt's type hint style, I'll keep it. Some linters might complain if `from __future__ import annotations` isn't used, but it's fine. I'll stick to the prompt.
   All good.✅
   Output matches. 
   [Done] 
   *Output Generation* (matches the refined 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)
   ```
   Perfect.✅
   Proceeds. 
   [Output Generation] -> *Outputs exactly the code block* (as requested)
   *(Note: I'll make sure formatting is correct)*
   All steps verified. No extra text. Ready. 
   [Final Check of the Prompt]: "Modify `add_job` to accept an optional priority parameter (default=0)" -> Done.
   "Higher priority jobs should be processed before lower priority jobs" -> Done (negated priority).
   "Jobs with the same priority should maintain FIFO order" -> Done (counter).
   "Add `get_next_job() -> tuple[str, dict] | None`" -> Done.
   "Write only the Python code, no explanations." -> Done.
   All constraints satisfied.✅
   Output matches. 
   [Proceeds]

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