<reasoning_content>
*   Task: Implement priority-based job scheduling for a `JobQueue` class.
    *    Requirements:
        1. `add_job` must accept `priority` (default=0).
        2. Higher priority jobs processed first.
        3. Same priority = FIFO.
        4. `get_next_job()` returns the highest priority job as a `tuple[str, dict]` or `None`.
    *    Priorities: 0 (Normal), 1 (High), 2 (Critical).
    *    Constraint: Only Python code, no explanations.

    *   To handle priority + FIFO (First In, First Out), a `heapq` (priority queue) is ideal.
    *   However, `heapq` is a min-heap. To treat higher numbers as higher priority, we need to store priorities as negative numbers or use a custom key.
    *   To maintain FIFO for the same priority, we need a secondary sort key: a counter (incrementing integer).
    *   Data structure: `heapq` storing `(-priority, entry_count, job_name, job_data)`.

    *   `__init__`: Initialize `self.heap = []` and `self.counter = 0`.
    *   `add_job(self, name, data, priority=0)`:
        *   Increment counter.
        *   Push `(-priority, self.counter, name, data)` into heap.
    *   `get_next_job(self) -> tuple[str, dict] | None`:
        *   If heap empty, return `None`.
        *   Pop from heap.
        *   Return `(name, data)`.

    *   `heapq.heappush(self.heap, (-priority, self.counter, name, data))`
    *   `heapq.heappop(self.heap)`

    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Higher priority number = higher priority.
            # heapq is a min-heap, so we negate priority.
            # Counter ensures FIFO for same priority.
            heapq.heappush(self.heap, (-priority, self.counter, name, data))
            self.counter += 1

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

    *   Requirement 1: `add_job` accepts optional priority (default=0). Yes.
    *   Requirement 2: Higher priority jobs processed first. Yes (using `-priority` in min-heap).
    *   Requirement 3: Same priority = FIFO. Yes (using `self.counter`).
    *   Requirement 4: `get_next_job` returns `tuple[str, dict] | None`. Yes.

    *   The user wants only Python code.

    Wait, let's double check the priority logic.
    If priority is 2 (Critical), -priority is -2.
    If priority is 0 (Normal), -priority is 0.
    -2 < 0, so `-2` comes first in a min-heap. Correct.

    Wait, let's re-read:
    "Higher priority jobs should be processed before lower priority jobs"
    "Priority levels: 0: Normal, 1: High, 2: Critical"
    So 2 is highest, 0 is lowest. Correct.

    Code style:
    Include imports. Use type hinting as requested in the prompt's signature.

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

    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
            # counter ensures FIFO order for same priority
            heapq.heappush(self.queue, (-priority, self.counter, name, data))
            self.counter += 1

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

    Wait, the prompt didn't specify typing for `add_job`, just `get_next_job`. I should stick to the signature provided.

    `get_next_job() -> tuple[str, dict] | None`

    Revised Code:
    ```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.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)
    ```

    Wait, the prompt asks to implement the queue based on the provided example. I should make sure the class name matches.

    Actually, let's check the logic one more time.
    Priority 2 (Critical) -> -2.
    Priority 1 (High) -> -1.
    Priority 0 (Normal) -> 0.
    Min-heap pops smallest first. -2 < -1 < 0. Correct.

    One edge case: If name is same? Doesn't matter because `counter` is unique and always incrementing.

    Final Polish:
    Just the code. No explanation.

    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # We use a min-heap. To make higher priority numbers come out first,
            # we store them as negative numbers.
            # 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
            
            priority_neg, count, name, data = heapq.heappop(self.queue)
            return (name, data)
    ```
    Actually, the prompt says `get_next_job() -> tuple[str, dict] | None`.

    Let's write it.
</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):
        # Since heapq is a min-heap, we store priority as a negative number
        # to ensure higher priority values are popped first.
        # 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
        
        _, _, name, data = heapq.heappop(self.queue)
        return (name, data)
```
</content>