<reasoning_content>
*   Goal: Implement priority-based job scheduling in a `JobQueue` class.
    *    Requirements:
        1.  `add_job(job_id, data, priority=0)`: Add job with priority.
        2.  Ordering: Higher priority first (2 > 1 > 0).
        3.  FIFO for same priority: If priority is equal, the one added first comes out first.
        4.  `get_next_job()`: Returns `(job_id, data)` or `None`.
    *    Constraints: Python code only, no explanations.

    *   I need a data structure that handles priorities efficiently. A `heapq` (Priority Queue) is standard.
    *   However, `heapq` is a min-heap. Since higher priority (2) should come first, I can either:
        a) Store priorities as negative values (e.g., priority 2 becomes -2, priority 0 becomes 0).
        b) Use a custom comparison or sort.
    *   To handle FIFO for same priority, I need a counter/sequence number to act as a tie-breaker.
    *   Entry structure in heap: `(priority_score, sequence_number, job_id, data)`.

    ```python
    import heapq
    import itertools

    class JobQueue:
        def __init__(self):
            self.queue = []
            self.counter = itertools.count()

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # We want higher numbers to be higher priority.
            # Since heapq is a min-heap, we use -priority.
            # We use the counter for FIFO stability.
            heapq.heappush(self.queue, (-priority, next(self.counter), job_id, data))

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

    *   `add_job`: accepts `job_id`, `data`, `priority=0`. Check.
    *   Higher priority first: `(-2, ...)` comes before `(-1, ...)`. Check.
    *   FIFO for same priority: `(-1, 0, ...)` comes before `(-1, 1, ...)`. Check.
    *   `get_next_job`: returns `tuple` or `None`. Check.

    *   Import `heapq` and `itertools`.
    *    Define `JobQueue` class.

    ```python
    import heapq
    import itertools

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Higher priority numbers should come out first.
            # Use negative priority to turn min-heap into max-priority behavior.
            # Use counter to ensure FIFO for same priority levels.
            heapq.heappush(self._heap, (-priority, next(self._counter)), job_id, data))

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

    Wait, `heapq.heappush(self._heap, (-priority, next(self._counter)), job_id, data))` is syntactically wrong. It should be a tuple.

    Correct: `heapq.heappush(self._heap, (-priority, next(self._counter)), job_id, data))` -> `heapq.heappush(self._heap, (-priority, next(self._counter), job_id, data))`

    Wait, let's refine the `add_job` signature to match the requirement: `add_job(job_id, data, priority=0)`.

    Wait, the prompt says: `queue.add_job("normal", {"type": " normal"}, priority=0)`. This means `job_id` is "normal", `data` is the dict.

    One detail: "higher priority jobs should be processed before lower priority jobs".
    Priority levels: 0 (Normal), 1 (High), 2 (Critical).
    So 2 is the highest.
    Heapq is min-heap.
    Priority 2 -> score -2.
    Priority 1 -> score -1.
    Priority 0 -> score 0.
    -2 is the smallest, so it comes out first. Correct.

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

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

        def add_job(self, job_id: str, data: Dict, priority: int = 0):
            # Use negative priority for max-heap behavior with heapq (min-heap)
            # Counter ensures FIFO for same priority
            entry = (-priority, next(self._counter), job_id, data)
            heapq.heappush(self._queue, entry)

        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, is the input strictly `(job_id, data, priority=0)`? Yes.
    One check on return type hint: `tuple[str, dict] | None` is valid in Python 3.10+.

    Let's make sure the class name and method names are exactly as asked.

    Requirements recap:
    1. `add_job` modified to accept `priority`.
    2. Higher priority processed first.
    3. FIFO for same priority.
    4. `get_next_job() -> tuple[str, dict] | None`.

    Example test:
    `queue.add_job("normal", {"type": " normal"}, priority=0)`
    `queue.add_job("critical", {"type": "critical"}, priority=2)`
    `queue.add_job("high", {"type": "high"}, priority=1)`

    Heap contents (prioritized):
    1. `(-2, 1, "critical", ...)`
    2. `(-1, 2, "high", ...)`
    3. `(0, 0, "normal", ...)` (Wait, counter is global).

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

    Heappop:
    -2 (smallest) -> `("critical", ...)`
    -1 -> `("high", ...)`
    0 -> `("normal", ...)`

    Perfect.

    Wait, I should ensure I only write the Python code.

    ```python
    import heapq
    import itertools

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Using negative priority because heapq is a min-heap, 
            # and higher priority numbers should be popped first.
            # The counter ensures FIFO order for jobs with the same priority.
            entry = (-priority, next(self._counter)), job_id, data
            # Wait, a tuple is needed.
            # entry = (-priority, next(self._counter)), job_id, data  <-- No
            # entry = (-priority, next(self._counter), job_id, data)
            pass
    ```
    Wait, I'll just write the code cleanly.

    ```python
    import heapq
    import itertools

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Using negative priority allows us to treat higher numbers 
            # as higher priority since heapq is a min-heap.
            # The counter ensures FIFO for same priority levels.
            entry = (-priority, next(self._counter), job_id, data)
            heapq.heappush(self._queue, entry)

        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 says `queue.add_job("normal", {"type": " normal"}, priority=0)`.
    So `job_id` is first argument, `data` is second. Correct.

    One minor detail: `tuple[str, dict] | None` is a Union type. Valid in recent versions. I'll use that.

    Check requirements again:
    1. Modify `add_job` to accept an optional priority parameter (default=0).
    2. Higher priority jobs should be processed before lower priority jobs.
    3. Jobs with the same priority should maintain FIFO order.
    4. Add `get_next_job()` to get the highest priority job.

    One thing: The prompt implies I should start from a base class or assume the structure. Since it says "Modify `add_job`" and "Add `get_next_job`", it assumes the existence of a `JobQueue` class.

    I will provide the full class definition for completeness.

    Final code structure:
    ```python
    import heapq
    import itertools
    from typing import Dict, Tuple, Optional

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

        def add_job(self, job_id: str, data: Dict, priority: int = 0):
            # We store (-priority, counter) to ensure that:
            # 1. Higher priorities (higher numbers) are popped first (min-heap).
            # 2. Jobs with same priority are ordered by arrival (FIFO).
            entry = (-priority, next(self._counter)), job_id, data # Error in logic
            # Correct logic:
            entry = (-priority, next(self._counter), job_id, data)
            heapq.heappush(self._queue, entry)

        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 type hint `tuple[str, dict] | None` is exactly what's requested in the prompt. I'll use that.

    Revised logic:
    ```python
    import heapq
    import itertools

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Use negative priority so that the highest priority number 
            # is treated as the "minimum" value for heapq.
            # sequence number ensures FIFO for equal priority levels.
            heapq.heappush(self._queue, (-priority, next(self._counter)), job_id, data))
    ```
    Wait, `heappush` signature is `heappush(list, item)`. `item` must be a tuple.
    So: `heapq.heappush(self._queue, (-priority, next(self._counter), job_id, data))`

    Final check on priority numbers:
    0: Normal
    1: High
    2: Critical
    -2 < -1 < 0. Correct.

    One last thing: the prompt asks for `get_next_job() -> tuple[str, dict] | None`. I'll match this exactly.

    ```python
    import heapq
    import itertools

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # Higher priority numbers are treated as higher priority.
            # By using -priority, the heap (min-heap) prioritizes the largest input.
            # next(self._counter) ensures FIFO for same priority levels.
            item = (-priority, next(self._counter), job_id, data)
            heapq.heappush(self._queue, item)

        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 requirements ask to "Modify `add_job`" and "Add `get_next_job`". I'll provide the whole class.
</reasoning_content>

<content>
```python
import heapq
import itertools

class JobQueue:
    def __init__(self):
        # Using a list to act as a heap
        self._queue = []
        # A counter to ensure FIFO order for jobs with the same priority
        self._counter = itertools.count()

    def add_job(self, job_id: str, data: dict, priority: int = 0):
        """
        Adds a job to the queue with a given priority level.
        Higher priority levels are processed first.
        """
        # We use negative priority because heapq is a min-heap. 
        # This ensures that a higher priority number (e.g., 2) 
        # becomes a smaller value (-2) and is popped first.
        # The counter acts as a tie-breaker to maintain FIFO order.
        entry = (-priority, next(self._counter), job_id, data)
        heapq.heappush(self._queue, entry)

    def get_next_job(self) -> tuple[str, dict] | None:
        """
        Returns the highest priority job as a tuple (job_id, data).
        Returns None if the queue is empty.
        """
        if not self._queue:
            return None
        
        # Pop the smallest value from the heap (which is the highest priority)
        _, _, job_id, data = heapq.heappop(self._queue)
        return (job_id, data)
```
</content>