<reasoning_content>
*   Task: Implement priority-based job scheduling for a queue.
    *    Requirements:
        1. `add_job` accepts optional `priority` (default=0).
        2. Higher priority jobs first.
        3. Same priority = FIFO (First-In-First-Out).
        4. `get_next_job()` returns `tuple[str, dict] | None`.
    *    Priority levels: 0 (Normal), 1 (High), 2 (Critical).
    *    Constraint: Write *only* the Python code, no explanations.

    *   Standard Python `heapq` is good for priority queues.
    *   However, `heapq` is a min-heap. If priorities are 0, 1, 2, and we want higher numbers first (Critical=2), we should store them as negative numbers or use a reversed logic.
    *   Wait, the requirements say "Higher priority jobs should be processed before lower priority jobs".
    *   Priority levels: 0=Normal, 1=High, 2=Critical.
    *   So, 2 is highest.
    *   To use a min-heap for max priority, we can store `(-priority, insertion_order, job_id, job_data)`.
    *   Alternatively, a simple list sorted by priority and insertion order, but that's $O(N)$ per insertion.
    *   Better: Use `heapq` with `(-priority, entry_count, job_id, job_data)`. `entry_count` ensures FIFO for same priority.

    *   `JobQueue` class.
    *   `self._queue` as a list (used with `heapq`).
    *   `self._count` to track insertion order.
    *   `add_job(job_id, data, priority=0)`:
        *   Push `(-priority, self._count, job_id, data)` into heap.
        *   Increment `self._count`.
    *   `get_next_job()`:
        *   Pop from heap.
        *   Return `(job_id, data)` or `None`.

    *   "Higher priority jobs should be processed before lower priority jobs".
    *   If 2 is Critical and 0 is Normal, then 2 > 0.
    *   So higher value = higher priority.
    *   `heapq` is a min-heap. So we store negative priority.

    *   `add_job(job_id, data, priority=0)`
    *   `get_next_job() -> tuple[str, dict] | None`

    ```python
    import heapq

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # We use -priority because heapq is a min-heap
            # self._count ensures FIFO for same priority
            heapq.heappush(self._queue, (-priority, self._count, job_id, data))
            self._count += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            _, _, job_id, data = heapq.heappop(self._queue)
            return (job_id, data)
    ```

    *   Requirement 1: `add_job` accepts optional `priority` (default=0). (Check)
    *   Requirement 2: Higher priority jobs before lower. (Check, -2 < -1 < -0).
    *   Requirement 3: Same priority = FIFO. (Check, `self._count` handles this).
    *   Requirement 4: `get_next_job()` returns `tuple[str, dict] | None`. (Check).

    Wait, let me double check the priority levels provided:
    0: Normal
    1: High
    2: Critical
    So 2 is indeed the highest priority. Using `-priority` in a min-heap ensures `(-2, ...)` comes before `(-1, ...)`.

    Code only. No explanations.

    Wait, one detail: `job_id` is usually a string in these types of prompts.

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

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

        def add_job(self, job_id: str, data: Dict, priority: int = 0):
            # Use negative priority to make heapq behave like a max-priority queue
            # Use self._count to maintain FIFO order for identical priorities
            heapq.heappush(self._queue, (-priority, self._count, job_id, data))
            self._count += 1

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

    Wait, the prompt example says:
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    `queue.add_job("critical", {"type": "critical"}, priority=2)`
    `queue.add_job("high", {"type": "high"}, priority=1)`
    `queue.get_next_job()` -> Returns "critical" job.

    In my logic:
    - `add_job("normal", ..., 0)` -> `(0, 0, "normal", ...)`
    - `add_job("critical", ..., 2)` -> `(-2, 1, "critical", ...)`
    - `add_job("high", ..., 1)` -> `(-1, 2, "high", ...)`

    Heap pops smallest first:
    1. `(-2, 1, "critical", ...)` -> Correct.
    2. `(-1, 2, "high", ...)` -> Correct.
    3. `(0, 0, "normal", ...)` -> Correct.

    Wait, my code used `(-priority, self._count, ...)`.
    Actually, the `self._count` should be the secondary sort key.
    If `priority` is the same, it compares `self._count`.
    Since `self._count` increases, it follows FIFO. Correct.

    Final check on return types: `tuple[str, dict] | None`.
    Python 3.10+ syntax for `|`. I'll use it.

    One small edge case: Does the user want `priority` to be an integer? Yes.
    Is `job_id` string? Yes.
    Is `data` dict? Yes.

    One final thought: The prompt asks for `get_next_job() -> tuple[str, dict] | None`.

    ```python
    import heapq

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Store negative priority to use min-heap as a max-priority queue
            # Use counter to ensure FIFO order for jobs with same priority
            heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            
            _, _, job_id, data = heapq.heappop(self._queue)
            return (job_id, data)
    ```

    Wait, the prompt example says:
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    The signature in prompt is `add_job(self, job_id, data, priority=0)`.
    Actually, looking at the example:
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    The first arg is `job_id`.
    The second arg is `data` (the dict).
    The third arg is `priority`.

    Ready to write.

    One detail: `tuple[str, dict] | None` syntax. It requires Python 3.10+. I will assume the environment supports it since the prompt used it.

    Wait, looking at the example again:
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    Is `job_id` "normal"? Yes.
    Is `data` `{"type": " normal"}`? Yes.

    Implementation:
    ```python
    import heapq

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Store as (-priority, counter, job_id, data)
            # -priority ensures highest priority value is popped first
            # counter ensures FIFO for same priority
            heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            
            _, _, job_id, data = heapq.heappop(self._queue)
            return (job_id, data)
    ```
    The prompt says "Write only the Python code, no explanations."

    Double check requirements:
    1. Modify `add_job` to accept an optional priority parameter (default=0). Done.
    2. Higher priority jobs processed before lower. Done (via negative).
    3. Same priority = FIFO. Done (via counter).
    4. `get_next_job()` returns `tuple[str, dict] | None`. Done.

    Wait, I should make sure `JobQueue` is defined. Yes.

    Is there anything else?
    "Modify `add_job` " implies I should probably write the class or the modified method. I'll provide the full class for completeness.

    Final check on types: `tuple[str, dict] | None`
    Should I use `typing`? The prompt didn't use `typing`. I'll stick to the provided signature.

    Wait, I just noticed the prompt says "Modify `add_job`". This implies a pre-existing structure. I will provide the class with the requested methods.

    One detail: "Higher priority jobs should be processed before lower priority jobs".
    Levels: 0: Normal, 1: High, 2: Critical.
    If I use `(-priority, counter)`, then for 2, I store `-2`. For 0, I store `0`.
    `-2` is smaller than `0`, so it pops first. Correct.

    ```python
    import heapq

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            
            _, _, job_id, data = heapq.heappop(self._queue)
            return (job_id, data)
    ```
    Wait, the prompt signature for `get_next_job` is `tuple[str, dict] | None`.
    In Python, `tuple` used as a generic requires `from __future__ import annotations` or Python 3.9+. I'll just write it as is.

    Actually, let me check the example again.
    `queue = JobQueue()`
    It doesn't define the class `JobQueue` in the snippet, so I must provide it.

    One more check: `tuple[str, dict]` is valid in Python 3.9+ even without imports.

    Wait, is there a simpler way without `heapq`?
    A simple list: `self._queue.append((priority, counter, job_id, data))` then `sort`. Or `bisect`.
    `heapq` is much cleaner for a priority queue.

    One final check: `job_id` vs `data`.
    Example: `queue.add_job("normal", {"type": " normal"}, priority=0)`
    `job_id` = "normal"
    `data` = `{"type": " normal"}`
    The result of `get_next_job()` should be `("critical", {"type": "critical"})`.
    My code does this.

    ```python
    import heapq

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Use negative priority to simulate a max-heap using heapq (min-heap)
            # Counter ensures FIFO order for equal priorities
            heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._queue:
                return None
            
            _, _, job_id, data = heapq.heappop(self._queue)
            return (job_id, data)
    ```
    Wait, I'll remove the comments just to be safe, though "no explanations" usually refers to text outside the code block.
</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, job_id: str, data: dict, priority: int = 0):
        # Use -priority to turn heapq (min-heap) into a max-priority queue
        # Use self._counter to ensure FIFO order for jobs with the same priority
        heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._queue:
            return None
        
        _, _, job_id, data = heapq.heappop(self._queue)
        return (job_id, data)
```
</content>