<reasoning_content>
Thinking Process:

1.  **Analyze the Request:**
    *   Goal: Implement a priority-based job scheduling queue in Python.
    *   Requirements:
        1.  Modify `add_job` to accept an optional `priority` parameter (default=0).
        2.  Higher priority jobs processed before lower priority jobs.
        3.  Same priority jobs maintain FIFO order.
        4.  Add `get_next_job() -> tuple[str, dict] | None` to retrieve the highest priority job.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical). Note: The example shows `priority=2` for critical and `priority=1` for high. This implies higher integer = higher priority.
    *   Output: Only Python code, no explanations.

2.  **Design the Data Structure:**
    *   I need a way to store jobs with priorities.
    *   Since I need to extract the highest priority job efficiently, a heap (priority queue) is suitable.
    *   However, standard Python `heapq` handles tuples. To maintain FIFO for equal priorities, I need to include a sequence counter in the heap item.
    *   Structure of a heap item: `(priority, sequence, job_id, job_data)`
    *   Wait, the requirement says "Higher priority jobs should be processed before lower priority jobs". In the example: `priority=2` (critical) comes before `priority=1` (high) comes before `priority=0` (normal). So higher integer = higher priority.
    *   `heapq` in Python is a min-heap. It pops the smallest element first.
    *   To make higher priority (larger number) pop first, I can negate the priority (e.g., store `-2` for critical, `-1` for high, `-0` for normal). Then `-2 < -1 < 0`, so `-2` comes first.
    *   Alternatively, I can use a `SortedList` or just sort a list every time (inefficient but simple). Given "queue" usually implies efficiency, a heap is better.
    *   Let's check the tuple return type: `tuple[str, dict]`. This implies `(job_id, job_metadata)`.
    *   FIFO for same priority: I need a monotonic counter to break ties.

3.  **Drafting the Class:**
    *   Class name: `JobQueue` (inferred from the example usage).
    *   `__init__`: Initialize empty list/heap and a counter.
    *   `add_job(self, job_id: str, job_data: dict, priority: int = 0)`:
        *   Store priority.
        *   Store counter for FIFO.
        *   Push to heap.
        *   Since `heapq` is min-heap, store `(-priority, counter, job_id, job_data)`.
    *   `get_next_job(self) -> tuple[str, dict] | None`:
        *   Pop from heap.
        *   Return `(job_id, job_data)`.
        *   Handle empty queue.

4.  **Refining Priority Logic:**
    *   Example: `priority=2` (Critical), `priority=1` (High), `priority=0` (Normal).
    *   Requirement: Higher priority processed first.
    *   Heap behavior: Smallest value pops first.
    *   To make 2 pop before 1: Store `-2` and `-1`. `-2 < -1`.
    *   So, key in heap: `(-priority, counter, job_id, job_data)`.
    *   Counter ensures stability (FIFO) for same priority.

5.  **Drafting 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)
   ```

6.  **Review against Constraints:**
    *   `add_job` accepts optional `priority` (default=0)? Yes.
    *   Higher priority processed before lower? Yes (using negation for min-heap).
    *   Same priority FIFO? Yes (using counter).
    *   `get_next_job` returns `tuple[str, dict] | None`? Yes.
    *   Example usage matches logic?
        *   `add_job(..., priority=0)` -> push `(-0, 0, ...)`
        *   `add_job(..., priority=2)` -> push `(-2, 1, ...)`
        *   `add_job(..., priority=1)` -> push `(-1, 2, ...)`
        *   Pop order:
            1.  `(-2, 1, ...)` (Critical)
            2.  `(-1, 2, ...)` (High)
            3.  `(-0, 0, ...)` (Normal)
        *   Matches requirement.

7.  **Final Code Structure:**
    *   Import heapq.
    *   Define class.
    *   Implement methods.
    *   Ensure type hints are correct.

8.  **One detail:** The prompt asks for "Write only the Python code". I should ensure no markdown blocks or extra text are outside the code block if possible, but usually, a code block is expected. I will provide the code inside a python block. Wait, the instruction says "Write only the Python code, no explanations." This usually means the output should be raw code or code inside a block. I will provide the code inside a markdown block for clarity, but keep text to a minimum. Actually, strictly "only the Python code" might mean no markdown ticks either, but standard practice for LLM responses is a markdown block. I will use a markdown block for safety.

    Wait, re-reading "Write only the Python code". I will output the code directly.

    Let's double check the return type hint syntax. `tuple[str, dict] | None` is valid in Python 3.10+. I'll use that.

    One minor optimization/simplification: Do I need to store `job_data` inside the tuple in the heap or just the reference? The requirement says `add_job("normal", {"type": "normal"}, priority=0)`. The second argument is a dict. I should store the dict directly in the heap.

    Let's write the code.

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

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

    def add_job(self, job_id: str, job_data: Dict[str, any], priority: int = 0) -> None:
        # Negate priority to use min-heap as max-heap (higher priority pops first)
        # Counter ensures FIFO for same priority
        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, `Dict[str, any]` is generic. The example uses `{"type": "normal"}`. I'll just use `dict` or `Dict` without generics to be safe/simple, or just `dict`. The return type hint in the prompt is `tuple[str, dict]`. I will match that.

    Revised 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 correct.

    One check on the return type hint: `tuple[str, dict] | None`. This requires Python 3.10+. The prompt implies modern Python. I will use it.

    Final check on requirements:
    1. `add_job` optional priority (default=0): Checked.
    2. Higher priority before lower: Checked (using -priority).
    3. Same priority FIFO: Checked (using counter).
    4. `get_next_job` signature: Checked.

    Ready.

    Wait, I should check if the prompt implies I should just write the class or include imports. "Implement priority-based job scheduling for the queue." usually implies the class definition. I will include imports.

    Wait, one detail in the example:
    `queue.add_job("normal", {"type": "normal"}, priority=0)`
    `job = queue.get_next_job()`
    The return value is used.
    The signature `get_next_job() -> tuple[str, dict] | None` is specific.

    I will write the code now.

    Wait, one more check. `tuple[str, dict] | None` is valid syntax for Python 3.10+. If the environment is older, `Optional[Tuple[str, dict]]` is safer. But I should follow the prompt's type hint style. The prompt explicitly wrote `tuple[str, dict] | None`. I will use that exact syntax.

    Also, `job_data` in `add_job` example is a dict. `job_data: dict` is fine.

    Let's assemble.

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

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)
```
    I'll remove `typing` imports if not strictly necessary, but `tuple` and `dict` are built-ins. `Optional` isn't used since I used `| None`.
    I'll stick to the prompt's type hint style.

    Wait, I need to make sure I don't use `any` in `job_data` type hint if I don't import it, but `dict` is fine.
    The prompt asks for "Write only the Python code".
    I will output the code block.

    One thing: The prompt example shows `job = queue.get_next_job()`.
    The return type is `tuple[str, dict]`.
    The function name is `get_next_job`.
    The class name is likely `JobQueue` based on `queue = JobQueue()`.

    Okay, final check on priority logic.
    Priority 2 (Critical) > Priority 1 (High) > Priority 0 (Normal).
    Heapq pops smallest.
    Store -2, -1, 0.
    -2 < -1 < 0.
    So -2 pops first. Correct.

    Counter ensures FIFO.
    Push order:
    1. Normal: (-0, 0, id1, data1)
    2. Critical: (-2, 1, id2, data2)
    3. High: (-1, 2, id3, data3)

    Heap contents:
    [(-2, 1, id2, data2), (-0, 0, id1, data1), (-1, 2, id3, data3)] (sorted internally)
    Pop 1: (-2, 1, id2, data2) -> Critical. Correct.
    Pop 2: (-1, 2, id3, data3) -> High. Correct.
    Pop 3: (-0, 0, id1, data1) -> Normal. Correct.

    If same priority:
    1. Normal: (-0, 0, id1, data1)
    2. Normal: (-0, 1, id2, data2)

    Heap: [(-0, 0, id1, data1), (-0, 1, id2, data2)]
    Pop 1: (-0, 0, id1, data1) -> id1. Correct (FIFO).

    Logic holds.

    One small detail: `job_data` in `add_job` signature. The prompt example passes `{"type": "normal"}`. It's a dict.
    The return type of `get_next_job` is `tuple[str, dict]`.
    I will use `dict` in the signature.

    Final check on constraints: "Write only the Python code, no explanations."
    I will provide the code inside a markdown block.

    Wait, should I include the example usage? The prompt says "Implement... for the queue." and shows an example. Usually, this means implement the class that makes the example work. I won't include the example usage in the output unless it's part of the implementation (e.g. `if __name__ == "__main__":`). I'll stick to the class definition to be safe and clean.

    Actually, looking at "Write only the Python code", providing the class is the core implementation. I will provide the class.

    One nuance: `tuple[str, dict] | None`. In Python 3.9 and below, `|` for type union requires `from __future__ import annotations` or specific syntax. Since I don't know the Python version, but the prompt uses the syntax, I will assume Python 3.10+ or future import context. I will just use the syntax requested.

    Wait, `job_data` in `add_job` example is `{"type": "normal"}`.
    In `get_next_job`, it returns `job_data`.
    So `job_data` must be preserved.

    Code looks solid.

```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)
```
    I will remove the type hints for `job_data` in `add_job` to match the example exactly if needed, but type hints are good practice. The prompt example `add_job("normal", {"type": "normal"}, priority=0)` implies the second argument is the data.
    I'll keep `job_data: dict`.

    Wait, I should check if `job_data` needs to be a specific type in the signature. The prompt says `get_next_job() -> tuple[str, dict] | None`. It doesn't explicitly specify `add_job` signature, but implies arguments. I will infer `job_id: str, job_data: dict`.

    One more thing: The prompt asks for `add_job` to accept an optional priority parameter (default=0).
    My code: `priority: int = 0`. Correct.

    Final check on "Write only the Python code". I will output the code block without markdown text outside.
    Actually, usually markdown blocks are preferred for code. I'll use markdown block.
    Wait, "Write only the Python code" might mean *no* markdown ticks either. But usually it means "don't write an essay". I will use markdown ticks to ensure it renders as code.
    Actually, to be safest with "only the Python code", I will output the raw text within the block.

    Wait, I'll just output the code block.

    One detail: `job_data` in `add_job`. The example passes `{"type": "normal"}`.
    So `job_data` is a dict.
    I will use `dict` in type hint.

    Okay, ready to generate.

    Wait, I need to make sure I don't import `typing` if I don't use it, to keep it minimal. `tuple` and `dict` are builtins. `heapq` is needed.
    I'll remove `typing` import to be cleaner, as `tuple` and `dict` are built-in types.

    Final check on priority logic again.
    "Higher priority jobs should be processed before lower priority jobs".
    Priority 2 (Critical) > Priority 0 (Normal).
    My code: `(-priority, ...)`
    If priority=2, item is -2.
    If priority=0, item is 0.
    -2 < 0.
    Heappop returns smallest.
    So -2 comes before 0.
    So Priority 2 comes before Priority 0.
    This matches "Higher priority jobs should be processed before lower priority jobs".
    Correct.

    What if priority is negative? The prompt defines levels 0, 1, 2. I assume non-negative.
    If priority was -5 (Super Critical), -(-5) = 5. 5 > -2.
    So 5 would pop after -2.
    So higher positive number = higher priority.
    If I had priority -5, it would be lower priority than 0 (since 5 > 0).
    Given the prompt defines levels 0, 1, 2, I don't need to worry about negative priorities.

    Okay, code is ready.

</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:
        # Negate priority for min-heap behavior (higher priority = smaller negative value)
        # Use counter to maintain FIFO order for same priority
        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>