<reasoning_content>
*   Goal: Implement priority-based job scheduling for a `JobQueue` class.
    *   Requirements:
        1.  `add_job(job_id, data, priority=0)`: Accept priority.
        2.  Priority ordering: Higher priority (higher number) first.
        3.  FIFO for same priority: Use a queue or keep track of arrival order.
        4.  `get_next_job() -> tuple[str, dict] | None`: Return the highest priority job.
    *   Priority levels: 0 (Normal), 1 (High), 2 (Critical).
    *   Constraint: Only Python code, no explanations.

    *   Need a data structure to store jobs.
    *   Since I need to sort by priority (desc) and then by insertion order (asc), a `heapq` (priority queue) is a standard approach.
    *   However, `heapq` is a min-heap. To get the highest priority first, I should store priorities as negative numbers OR use a custom ordering.
    *   To handle FIFO for same priority in a heap, I need a tie-breaker (like a counter).
    *   Alternatively, I can just use a list and sort it, but that's $O(N \log N)$ or $O(N)$ per pop. A heap is $O(\log N)$.
    *   Let's go with `heapq`.

    *   `self.jobs`: A list to be used as a heap.
    *   `self.counter`: An integer to act as a tie-breaker to ensure FIFO for equal priorities.

    *   `add_job(job_id, data, priority=0)`:
        *   Push `(-priority, counter, job_id, data)` into the heap.
        *   Increment counter.
    *   `get_next_job()`:
        *   If heap is empty, return `None`.
        *   Pop the smallest element (which will be the most negative priority, i.e., highest priority).
        *   Return `(job_id, data)`.

    *   `priority=2` (Critical) becomes `-2` in the heap.
    *   `priority=1` (High) becomes `-1`.
    *   `priority=0` (Normal) becomes `0`.
    *   `heapq.heappop` returns the smallest value. `-2` is smaller than `-1`, so it pops correctly.
    *   The `counter` ensures that if priorities are equal, the one with the lower counter (added earlier) is popped first.

    ```python
    import heapq

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

        def add_job(self, job_id: str, data: dict, priority: int = 0):
            # We use -priority because heapq is a min-heap,
            # and we want the highest priority value to be processed first.
            # counter ensures FIFO for same priority.
            heapq.heappush(self.jobs, (-priority, self.counter, job_id, data))
            self.counter += 1

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

    *   Requirement 1: `add_job` accepts priority (default 0). Yes.
    *   Requirement 2: Higher priority first. Yes (using negative values in min-heap).
    *   Requirement 3: Same priority = FIFO. Yes (using `self.counter`).
    *   Requirement 4: `get_next_job()` signature and logic. Yes.
</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, job_id: str, data: dict, priority: int = 0):
        # Use negative priority because heapq is a min-heap.
        # Higher priority numbers will become smaller negative numbers.
        # counter ensures FIFO order for identical priorities.
        heapq.heappush(self.jobs, (-priority, self.counter, job_id, data))
        self.counter += 1

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