<reasoning_content>
*   Goal: Implement priority-based job scheduling in a queue.
    *    Requirements:
        1.  `add_job(job_id, data, priority=0)`: Add a job with priority.
        2.  Higher priority jobs first (Priority: 0=Normal, 1=High, 2=Critical).
        3.  Same priority = FIFO (First In, First Out).
        4.  `get_next_job() -> tuple[str, dict] | None`: Get the highest priority job.
    *    Data Structure: A Priority Queue (using `heapq` or a list that is sorted, but a heap is more efficient for priority management). Since we need FIFO for same priority, we should include an entry count or timestamp.

    *   `heapq` in Python implements a min-heap.
    *   Priority levels provided: 0 (Normal), 1 (High), 2 (Critical).
    *   Requirement says "Higher priority jobs should be processed before lower priority jobs".
    *   Usually, in `heapq`, the smallest value comes out first.
    *   If I want "Critical" (2) to come first, I should treat higher numbers as higher priority. However, standard `heapq` pops the minimum.
    *   Wait, let's look at the example:
        - "normal" priority 0
        - "critical" priority 2
        - "high" priority 1
        - Result: "critical" (priority 2) comes first.
    *   So, higher number = higher priority. To use a min-heap, I can store priorities as negative numbers. Or I can use a custom comparator/structure.
    *   To ensure FIFO for same priority, I need a secondary sorting key: an incrementing counter.

    *   Structure: `self.heap = []`.
    *   Counter: `self.count = 0`.
    *   `add_job(job_id, data, priority=0)`:
        *   Store as `(-priority, self.count, job_id, data)`.
        *   Increment `self.count`.
        *   `heapq.heappush(...)`.
    *   `get_next_job()`:
        *   If heap empty, return `None`.
        *   `heapq.heappop(...)`.
        *   Return `(job_id, data)`.

    ```python
    import heapq

    class JobQueue:
        def __init__(self):
            self.heap = []
            self.counter = 0

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Use -priority because heapq is a min-heap and we want higher values first
            # Use counter to ensure FIFO for same priority
            heapq.heappush(self.heap, (-priority, self.counter, job_id, data))
            self.counter += 1

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

    *   `add_job` signature matches.
    *   Priority 2 comes before 1, 1 before 0. Correct.
    *   FIFO for same priority? Yes, because `self.counter` is used as the second element in the tuple.
    *   `get_next_job` signature matches.
    *   Returns `(job_id, data)` or `None`.

    Actually, looking at the prompt: "Higher priority jobs should be processed before lower priority jobs".
    Level 2 (Critical) > Level 1 (High) > Level 0 (Normal).
    Using `-priority` ensures 2 is "smaller" than 1 in a min-heap (-2 < -1).

    Wait, looking at the example again:
    `queue.add_job("normal", ..., priority=0)`
    `queue.add_job("critical", ..., priority=2)`
    `queue.add_job("high", ..., priority=1)`
    `queue.get_next_job()` -> "critical"

    Yes, `-priority` handles this correctly.

    One detail: `tuple[str, dict] | None`.
    Type hints require `from __future__ import annotations` if using `|` in older Python, but since it's a coding prompt, I'll stick to the standard syntax or just provide the code. The prompt asks for "only the Python code".

    Let's refine the class 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, data: Dict, priority: int = 0) -> None:
            # Use negative priority because heapq is a min-heap.
            # Higher priority (larger number) becomes a smaller negative number.
            # Counter ensures FIFO for same priority.
            heapq.heappush(self._queue, (-priority, self._counter, job_id, data))
            self._counter += 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, I should check if I need any specific imports. `heapq` is built-in.

    Checking the example one more time:
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    `queue.add_job("critical", {"type": "critical"}, priority=2)`
    `queue.add_job("high", {"type": "high"}, priority=1)`
    Result: "critical".

    My logic:
    Heap:
    1. `(-0, 0, "normal", ...)`
    2. `(-2, 1, "critical", ...)`
    3. `(-1, 2, "high", ...)`

    Heap min:
    `(-2, 1, "critical", ...)` is the smallest. Correct.

    Next min:
    `(-1, 2, "high", ...)` is next. Correct.

    Last:
    `(-0, 0, "normal", ...)` Correct.

    Final check on types:
    `get_next_job() -> tuple[str, dict] | None`
    I will use standard types.

    One small detail: the prompt says "Write only the Python code, no explanations."

    I will define the `JobQueue` class.

    ```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) -> None:
            # Store as (-priority, count) to use heapq as a max-priority queue 
            # with FIFO ordering for ties.
            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)

    ```

    Wait, should I include the example code? The prompt says "Write only the Python code". Usually, this means the implementation.

    I'll provide the `JobQueue` class implementation.

    Wait, `tuple[str, dict] | None` is Python 3.10+ syntax. I'll assume modern Python.

    Double checking `add_job` signature.
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    The prompt says "Modify `add_job` to accept an optional priority parameter". This implies there was an existing class or I'm defining the whole thing. I'll define the whole class.

    Wait, "Modify ... " implies a snippet? Usually, these tasks want a complete working class if not specified.

    Final check on requirements:
    1. `add_job` optional priority = 0. (Done)
    2. Higher priority before lower. (Done via -priority)
    3. Same priority FIFO. (Done via counter)
    4. `get_next_job` returns tuple or None. (Done)

    One thing: `tuple[str, dict] | None` is exactly what the prompt asks for.

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

    Actually, should I use `typing`? The prompt uses `tuple[str, dict] | None` which is native in 3.10. No need for typing library.

    Wait, the prompt 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)`

    My code will handle this perfectly.

    One minor thing:
    `queue.get_next_job() # Returns critical job first`
    Since `critical` was added second (counter=1) and `high` was added third (counter=2), if they had same priority, `critical` would come first. Correct.

    I'll provide the code now.
</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) -> None:
        # Use negative priority to turn heapq (min-heap) into a max-priority queue.
        # The counter ensures 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>