<reasoning_content>
*   Task: Implement priority-based job scheduling in a `JobQueue` class.
    *    Requirements:
        1.  `add_job(name, data, priority=0)`: Add job with priority.
        2.   Higher priority jobs first (higher number = higher priority).
        3.   FIFO for equal priorities.
        4.   `get_next_job() -> tuple[str, dict] | None`: Retrieve and remove the highest priority job.
    *    Priority levels: 0 (Normal), 1 (High), 2 (Critical).
    *    Output: Only Python code.

    *   A `heapq` (min-heap) is usually the go-to for priority queues in Python.
    *   However, `heapq` is a min-heap. To make it a max-heap for "higher priority first", we can store the priority as a negative value.
    *   To maintain FIFO for same priorities, we need a counter (entry count) to serve as a tie-breaker.
    *   Structure of a job entry: `(-priority, entry_count, name, data)`.

    *   `self.jobs`: A list to act as a heap.
    *   `self.counter`: An integer to ensure FIFO for same priorities.

    *   `add_job(name, data, priority=0)`:
        *   Push `(-priority, self.counter, name, data)` onto the heap.
        *   Increment `self.counter`.
    *   `get_next_job()`:
        *   If heap is empty, return `None`.
        *   Pop from heap.
        *   Return `(name, data)`.

    *   `queue.add_job("normal", {"type": "normal"}, priority=0)` -> Heap: `[(0, 0, "normal", {...})]`
    *   `queue.add_job("critical", {"type": "critical"}, priority=2)` -> Heap: `[(-2, 1, "critical", {...}), (0, 0, "normal", {...})]`
    *   `queue.add_job("high", {"type": "high"}, priority=1)` -> Heap: `[(-2, 1, "critical", {...}), (-1, 2, "high", {...}), (0, 0, "normal", {...})]`
    *   `get_next_job()`:
        *   Pop `(-2, 1, "critical", {...})`.
        *   Return `("critical", {...})`. Correct.

    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Use negative priority for max-heap behavior with heapq
            # counter ensures FIFO for same priority
            heapq.heappush(self.jobs, (-priority, self.counter, name, data))
            self.counter += 1

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

    *   Requirement 1: `add_job` accepts `priority` default 0. (Check)
    *   Requirement 2: Higher priority first. (Check, via `-priority`)
    *   Requirement 3: Same priority FIFO. (Check, via `self.counter`)
    *   Requirement 4: `get_next_job` signature. (Check)

    *   Wait, does "higher priority" mean higher number?
        *   Example says: `priority=2` is "Critical", `priority=1` is "High", `priority=0` is "Normal".
        *   The example says "Returns critical job first".
        *   So yes, higher number = higher priority.

    *   Writing the code block.

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

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # We use -priority because heapq is a min-heap.
            # We use counter to maintain FIFO for identical priorities.
            heapq.heappush(self.jobs, (-priority, self.counter, name, data))
            self.counter += 1

        def get_next_job(self) -> Optional[Tuple[str, dict]] :
            if not self.jobs:
                return None
            
            # Pop the element with the lowest value (highest -priority )
            _, _, name, data = heapq.heappop(self.jobs)
            return (name, data)
    ```

    Actually, the prompt says `tuple[str, dict] | None`, so I should stick to that syntax or standard type hinting if requested. The prompt says "Write only the Python code".

    Double check the result of `get_next_job` when heap is empty. `None`. Correct.

    Wait, `tuple` hint usage. `tuple[str, dict]` is Python 3.9+.

    Final Structure:
    ```python
    import heapq

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

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Use negative priority to simulate a max-heap using heapq (min-heap)
            # The count ensures FIFO order for jobs with the same priority
            heapq.heappush(self.jobs, (-priority, self.count, name, data))
            self.count += 1

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

    Let's verify the example order.
    1. "normal", priority 0 -> `(-0, 0, "normal", ...)`
    2. "critical", priority 2 -> `(-2, 1, "critical", ...)`
    3. "high", priority 1 -> `(-1, 2, "high", ...)`
    Heap state: `[(-2, 1, ...), (-1, 2, ...), (0, 0, ...)]`
    Pop 1: `(-2, 1, ...)` -> "critical"
    Correct.
</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # heapq is a min-heap. To prioritize higher numbers, we store negative priority.
        # The counter ensures FIFO behavior for jobs with the same priority level.
        heapq.heappush(self.jobs, (-priority, self.counter, name, data))
        self.counter += 1

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