<reasoning_content>
Thinking Process:

1.  **Deconstruct the Request:**
    *   Goal: Implement priority-based job scheduling for a queue.
    *   Requirements:
        *   `add_job` accepts optional `priority` parameter (default=0).
        *   Higher priority processed first.
        *   Same priority maintains FIFO.
        *   `get_next_job() -> tuple[str, dict] | None` returns highest priority job.
        *   Priority levels: 0 Normal, 1 High, 2 Critical.
        *   Output: Only Python code, no explanations.

2.  **Design the Data Structure:**
    *   I need a queue that supports priority ordering and FIFO for equal priorities.
    *   Standard `queue.Queue` doesn't support priority natively in a way that allows easy insertion with priority while maintaining FIFO for equals (though `heapq` can do this).
    *   `heapq` is perfect for this. It maintains a min-heap.
    *   To use `heapq` for a max-heap behavior (higher number = higher priority), I can negate the priority.
    *   To maintain FIFO for equal priorities, I need a tie-breaker. A monotonic counter or sequence number works well. Since `heapq` compares tuples element by element, `(neg_priority, sequence_number, job_data)` will sort by `neg_priority` first, then `sequence_number`.
    *   `sequence_number` ensures that if `neg_priority` is equal, the one with the lower `sequence_number` (added earlier) comes first.

3.  **Draft the Class:**
    *   Class name: `JobQueue` (implied by the example usage `queue = JobQueue()`).
    *   Imports: `heapq`, `itertools` (for counter), `typing` (for type hints).

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

    *   Initialization:
        ```python
        class JobQueue:
            def __init__(self):
                self._heap = []
                self._counter = count() # Monotonic counter for FIFO
        ```

    *   `add_job` method:
        *   Signature: `add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None`
        *   Logic: Push to heap. Tuple structure: `(-priority, next(counter), job_name, job_data)`.
        *   Note: The requirement says `get_next_job` returns `tuple[str, dict]`. So I need to store `job_name` and `job_data`.
        *   Code:
            ```python
            def add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None:
                heapq.heappush(self._heap, (-priority, next(self._counter), job_name, job_data))
            ```

    *   `get_next_job` method:
        *   Signature: `get_next_job(self) -> Optional[Tuple[str, dict]]`
        *   Logic: Pop from heap. Return `(job_name, job_data)`.
        *   Code:
            ```python
            def get_next_job(self) -> Optional[Tuple[str, dict]]:
                if not self._heap:
                    return None
                neg_pri, seq, name, data = heapq.heappop(self._heap)
                return (name, data)
            ```

4.  **Review against Requirements:**
    *   `add_job` accepts optional priority? Yes, `priority: int = 0`.
    *   Higher priority processed first? Yes, `-priority` ensures 2 becomes -2, 1 becomes -1, 0 becomes 0. -2 < -1 < 0, so 2 comes first. Yes.
    *   Same priority FIFO? Yes, `next(self._counter)` increases, so smaller counter comes first. Yes.
    *   `get_next_job` returns `tuple[str, dict] | None`? Yes.
    *   Priority levels mentioned? The code supports arbitrary integers, which covers 0, 1, 2. The example uses these. The code doesn't need to enforce levels, just support them. The requirement lists levels as info, not necessarily validation logic. Usually, in these coding tasks, supporting the logic is sufficient.
    *   Example usage check:
        ```python
        queue = JobQueue()
        queue.add_job("normal", {"type": "normal"}, priority=0)
        queue.add_job("critical", {"type": "critical"}, priority=2)
        queue.add_job("high", {"type": "high"}, priority=1)
        
        job = queue.get_next_job() 
        # Heap state before pop:
        # [(-2, 1, "critical", ...), (-1, 2, "high", ...), (0, 0, "normal", ...)]
        # Note: counter values depend on order.
        # 1. add normal: (-0, 0, "normal", ...)
        # 2. add critical: (-2, 1, "critical", ...)
        # 3. add high: (-1, 2, "high", ...)
        # Heapify/Heappush maintains order.
        # Pop returns (-2, 1, ...).
        # Returns ("critical", ...). Correct.
        ```

5.  **Refine Code Structure:**
    *   Add type hints for completeness.
    *   Ensure imports are present.
    *   Result should be clean Python code.

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

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

        def add_job(self, job_name: str, job_data: Dict, priority: int = 0) -> None:
            heapq.heappush(self._heap, (-priority, next(self._counter), job_name, job_data))

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

6.  **Final Polish:**
    *   The prompt asks for "Write only the Python code".
    *   The code looks solid.
    *   `Tuple[str, dict] | None` syntax is valid in Python 3.10+. If the environment is older, `Optional[Tuple[str, dict]]` is safer. The prompt uses `|`, suggesting modern Python. I'll use `Optional` or `|` consistently. The prompt uses `|` in the requirement description, so I can use `|` in the code or `Optional`. I'll use `Optional` for broader compatibility or just follow the prompt's style. The prompt's example `tuple[str, dict] | None` implies Python 3.10+. I'll use `from typing import Optional, Tuple, Dict` and `Optional[Tuple[str, Dict]]` to be safe, or just use the `|` syntax. Given the prompt uses `|`, I'll use `|`.
    *   Actually, `tuple[str, dict] | None` is Python 3.10. `Optional` is 3.5+. I'll use `Optional` to be robust, or match the prompt. Matching the prompt is usually best.
    *   Result:
        ```python
        import heapq
        from itertools import count
        from typing import Optional, Tuple, Dict

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

            def add_job(self, job_name: str, job_data: Dict, priority: int = 0) -> None:
                heapq.heappush(self._heap, (-priority, next(self._counter), job_name, job_data))

            def get_next_job(self) -> Optional[Tuple[str, Dict]]:
                if not self._heap:
                    return None
                _, _, job_name, job_data = heapq.heappop(self._heap)
                return job_name, job_data
        ```
    *   Wait, the prompt says `tuple[str, dict] | None`. If I output code, I should probably output valid code. `Optional` is standard. I'll stick to `Optional` or `|`. I'll use `Optional` as it's universally understood in typing contexts even if `|` is used in the prompt, but the prompt explicitly wrote `|`. I'll use `|` to match the user's mental model.
    *   Also, `Dict` vs `dict`. Prompt uses `dict`. I'll use `dict`.
    *   Final code block.

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

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

        def add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None:
            heapq.heappush(self._heap, (-priority, next(self._counter), job_name, job_data))

        def get_next_job(self) -> Optional[Tuple[str, dict]]:
            if not self._heap:
                return None
            _, _, job_name, job_data = heapq.heappop(self._heap)
            return job_name, job_data
    ```
    This looks correct and complete.

</reasoning_content>

<content>
```python
import heapq
from itertools import count
from typing import Optional, Tuple

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

    def add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._heap, (-priority, next(self._counter), job_name, job_data))

    def get_next_job(self) -> Optional[Tuple[str, dict]]:
        if not self._heap:
            return None
        _, _, job_name, job_data = heapq.heappop(self._heap)
        return job_name, job_data
```
</content>