<reasoning_content>
*   Goal: Implement priority-based job scheduling.
    *   Requirements:
        1.  `add_job(name, data, priority=0)`: Accepts a priority.
        2.  Higher priority first (Critical > High > Normal).
        3.  Same priority = FIFO.
        4.  `get_next_job() -> tuple[str, dict] | None`: Get highest priority job.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical). Note: Usually, priority queues use lower numbers as higher priority (like `heapq`), but the prompt says "Higher priority jobs should be processed before lower priority jobs" and explicitly lists 2 as Critical and 0 as Normal. This means 2 > 1 > 0.
    *   Structure: Need a queue that preserves order for same priority. A list of lists or a priority queue with a counter is standard.

    *   `heapq` is the standard tool for priority queues in Python.
    *   `heapq` implements a min-heap (lowest value first).
    *   Since 2 is the highest priority and 0 is the lowest, I need to invert the priority value (e.g., use `-priority`) to make it a max-heap behavior using `heapq`, OR I can just use a list of queues/deques where index represents priority.
    *   However, for a small number of levels (0, 1, 2), a dictionary of `collections.deque` objects is very efficient and clean.
    *   Wait, the requirement is "Higher priority jobs should be processed before lower priority jobs".
    *   Let's look at the example:
        - `add_job("normal", ..., priority=0)`
        - `add_job("critical", ..., priority=2)`
        - `add_job("high", ..., priority=1)`
        - `get_next_job()` -> returns `critical` (priority 2).
    *   So, Priority 2 > 1 > 0.

    *Approach A: `heapq`*
    - Store entries as `(-priority, entry_count, name, data)`.
    - `entry_count` ensures FIFO for same priority.
    - `priority` negated because `heapq` is a min-heap.

    *Approach B: Dictionary of Deques*
    - `self.queues = {2: deque(), 1: deque(), 0: deque()}`
    - `add_job` appends to `self.queues[priority]`.
    - `get_next_job` checks 2, then 1, then 0.

    Approach B is very readable and directly handles the FIFO requirement naturally.

    Let's refine Approach B:
    ```python
    from collections import deque

    class JobQueue:
        def __init__(self):
            self.queues = {2: deque(), 1: deque(), 0: deque()}

        def add_job(self, name: str, data: dict, priority: int = 0):
            if priority not in self.queues:
                # Fallback or handle invalid priority?
                # Prompt says levels are 0, 1, 2.
                # Let's just ensure it's in there.
                self.queues[priority] = deque()
            self.queues[priority].append((name, data))

        def get_next_job(self) -> tuple[str, dict] | None:
            for p in [2, 1, 0]:
                if self.queues[p]:
                    return self.queues[p].popleft()
            return None
    ```

    Wait, "Higher priority jobs should be processed before lower priority jobs".
    The example says:
    - `priority=0` (Normal)
    - `priority=2` (Critical)
    - `priority=1` (High)
    Result: Critical (2) first.
    So 2 > 1 > 0.

    Let's double check the priority values.
    0: Normal
    1: High
    2: Critical
    Yes, larger numbers are higher priority.

    Is there a constraint on the number of priorities? The prompt doesn't say it's *only* 0, 1, 2, but those are the levels given. A priority queue approach (heapq) is more robust if arbitrary priorities are allowed.

    *Approach C: `heapq`*
    ```python
    import heapq
    from dataclasses import dataclass, field
    from typing import Any

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # heapq is a min-heap.
            # To make higher numbers higher priority, we use negative.
            heapq.heappush(self.queue, (-priority, self.counter, name, data))
            self.counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self.queue:
                return None
            neg_priority, _, name, data = heapq.heappop(self.queue)
            return (name, data)
    ```
    This handles arbitrary priorities and maintains FIFO via the `counter`.

    Let's look at the prompt again. "Higher priority jobs should be processed before lower priority jobs". This applies to the numbers provided.

    Let's stick to a simple implementation that works with the provided examples.

    Actually, the list of deques is very clean. But the `heapq` is standard for "Priority Queues". I'll use `heapq`.

    Wait, let me re-read the requirements.
    1. Modify `add_job` to accept optional priority (default=0).
    2. Higher priority jobs processed before lower.
    3. Same priority = FIFO.
    4. `get_next_job()`.

    One detail: `tuple[str, dict] | None`. This type hinting suggests Python 3.10+.

    Let's write the `JobQueue` class.

    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Use negative priority because heapq is a min-heap
            # and we want higher numbers to be popped first.
            # counter ensures FIFO for same priority.
            heapq.heappush(self._queue, (-priority, self._counter, name, data))
            self._counter += 1

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

    Check FIFO requirement:
    - Job A: priority 1, counter 0
    - Job B: priority 1, counter 1
    - Heap: `[(-1, 0, A, ...), (-1, 1, B, ...)]`
    - `heappop` returns `(-1, 0, A, ...)` first. Correct.

    Check Priority:
    - Job A: priority 1, counter 0
    - Job B: priority 2, counter 1
    - Heap: `[(-2, 1, B, ...), (-1, 0, A, ...)]`
    - `heappop` returns `(-2, 1, B, ...)` first. Correct.

    Final check on signature:
    `add_job(self, name: str, data: dict, priority: int = 0)`
    `get_next_job(self) -> tuple[str, dict] | None`

    One minor thing: The prompt asks to "Modify `add_job`". This implies there might be an existing class. I will provide the class structure.

    Actually, looking at the prompt "Implement priority-based job scheduling for the queue", I should provide the `JobQueue` class definition.

    Code:
    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Higher priority value means higher priority.
            # heapq is a min-heap, so we negate the priority.
            # The counter ensures FIFO for identical priorities.
            heapq.heappush(self._queue, (-priority, self._count, name, data))
            self._count += 1

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

    Wait, is there any ambiguity about "Higher priority"?
    Usually, priority 1 is higher than 0.
    Prompt:
    0: Normal
    1: High
    2: Critical
    Clearly, 2 is the "highest" priority.

    Is there any restriction on the order of items in the tuple?
    `tuple[str, dict]`
    The name is `str`, the data is `dict`.
    Example: `queue.add_job("normal", {"type": "normal"}, priority=0)`
    `queue.get_next_job()` -> `("critical", {"type": "critical"})`

    Ready.
</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # heapq is a min-heap. To treat higher priority numbers 
        # (e.g., 2) as higher priority, we negate the value.
        # The counter ensures FIFO order for jobs with the same priority.
        heapq.heappush(self._queue, (-priority, self._counter, name, data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._queue:
            return None
        
        # pop the item with the lowest negated priority (highest actual priority)
        _, _, name, data = heapq.heappop(self._queue)
        return (name, data)
```
</content>