<reasoning_content>
Thinking Process:

1.  **Analyze the Request:**
    *   Goal: Implement a priority-based job scheduling queue in Python.
    *   Requirements:
        1.  `add_job` method needs an optional `priority` parameter (default 0).
        2.  Higher priority jobs processed before lower priority jobs.
        3.  FIFO order for same priority.
        4.  `get_next_job()` method returns `tuple[str, dict] | None`.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical). Note: The example shows `priority=2` for critical and `priority=1` for high. This implies *higher number = higher priority*.
    *   Output: Only Python code, no explanations.

2.  **Determine Data Structure:**
    *   To support priority + FIFO, a simple list isn't efficient for insertion (O(n)) if we want to maintain order, though acceptable for small queues.
    *   `heapq` is the standard library tool for priority queues.
    *   However, `heapq` is a min-heap. To make higher numbers come out first (2 before 1 before 0), we can negate the priority or use a custom comparison.
    *   Negating priority: Priority 2 becomes -2, Priority 0 becomes 0. -2 < 0, so -2 comes out first. This works.
    *   To maintain FIFO for same priority, we need a tie-breaker. Since `heapq` compares tuples element-wise, we can include a sequence counter (timestamp/counter) in the tuple.
    *   Tuple structure: `(-priority, sequence_counter, job_id, job_data)`
    *   Wait, the requirement says `get_next_job() -> tuple[str, dict] | None`. The return value should be `(job_name, job_attributes)`.
    *   So the heap item needs to store enough info to reconstruct this.
    *   Let's refine the heap item: `(-priority, insertion_index, job_name, job_data)`.
    *   `insertion_index` ensures FIFO stability for equal priorities.

3.  **Drafting the Code:**
    *   Import `heapq`.
    *   Class `JobQueue`.
    *   `__init__`: Initialize `self.heap`, `self.counter`.
    *   `add_job(self, job_name: str, job_data: dict, priority: int = 0)`:
        *   Increment counter.
        *   Push `(-priority, counter, job_name, job_data)` to heap.
    *   `get_next_job(self) -> tuple[str, dict] | None`:
        *   If heap empty, return `None`.
        *   Pop from heap.
        *   Return `(job_name, job_data)`.

4.  **Refining Priority Logic:**
    *   Requirement: "Higher priority jobs should be processed before lower priority jobs".
    *   Example: `priority=2` (Critical) before `priority=1` (High) before `priority=0` (Normal).
    *   Heapq is a min-heap. Smallest element comes out first.
    *   If I push `2`, `1`, `0`. `0` comes out first.
    *   If I push `-2`, `-1`, `0`. `-2` is smallest. `-2` comes out first.
    *   So negating priority works.
    *   Tie-breaking: `(-priority, counter)`. Since counter increases, smaller counter comes out first.
    *   Order: `(-priority, counter, name, data)`.
    *   Example trace:
        *   `add_job("normal", ..., 0)` -> `(-0, 0, "normal", ...)`
        *   `add_job("critical", ..., 2)` -> `(-2, 1, "critical", ...)`
        *   `add_job("high", ..., 1)` -> `(-1, 2, "high", ...)`
        *   Heap: `[(-2, 1, ...), (-1, 2, ...), (0, 0, ...)]` (conceptual order).
        *   Pop: `(-2, 1, ...)` -> Critical. Correct.
        *   Next: `(-1, 2, ...)` -> High. Correct.
        *   Next: `(0, 0, ...)` -> Normal. Correct.

5.  **Reviewing Constraints:**
    *   "Write only the Python code, no explanations."
    *   Type hints should be included if possible (based on the prompt's usage of `-> tuple[str, dict] | None`).
    *   Ensure imports are present.

6.  **Final Code Structure:**
    ```python
    import heapq

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

        def add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None:
            # Negate priority because heapq is a min-heap
            # Counter ensures FIFO for same priority
            heapq.heappush(self._heap, (-priority, self._counter, job_name, job_data))
            self._counter += 1

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

7.  **Checking Edge Cases:**
    *   Empty queue: `get_next_job` returns `None`. Handled.
    *   Same priority: Counter handles ordering. Handled.
    *   Priority values: Example uses 0, 1, 2. Logic handles arbitrary integers where higher is better.

8.  **Final Polish:**
    *   Ensure strict adherence to "no explanations".
    *   Ensure type hints match the prompt's `tuple[str, dict] | None`. Note: `|` syntax requires Python 3.10+. Standard practice for recent code is fine.

    Let's double check the prompt example usage:
    ```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()  # Returns critical job first
    ```
    The example passes `job_name` as first arg, `dict` as second.
    My signature: `add_job(self, job_name: str, job_data: dict, priority: int = 0)`. Matches.

    One minor detail: The prompt asks for `tuple[str, dict] | None`. In Python 3.9 and earlier, `tuple[str, dict]` is valid but `|` union syntax might not be (requires 3.10+). Assuming modern Python environment given the syntax in the prompt.

    Wait, `job_name` is a string, `job_data` is a dict.
    The prompt says `get_next_job() -> tuple[str, dict] | None`.
    My implementation returns `(job_name, job_data)`. This matches.

    Ready to write.

    One check on imports: `heapq` is standard.
    One check on syntax: `|` for union types.
    One check on logic: Negated priority for max-heap behavior on min-heap. Counter for stability.

    Wait, is there any specific constraint on method signatures other than `add_job` and `get_next_job`? No.
    I will wrap it in a class structure.

    Wait, I should check if the prompt implies a global function or a class.
    "Implement priority-based job scheduling for the queue."
    Example: `queue = JobQueue()`.
    So it's a class.

    Final check on code:
    ```python
    import heapq
    from typing import Optional, Tuple, Dict

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

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

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._heap:
                return None
            _, _, job_name, job_data = heapq.heappop(self._heap)
            return (job_name, job_data)
    ```
    Looks good. I will remove type hints imports to keep it cleaner if possible, but strict type hinting is good. The prompt uses `tuple[str, dict] | None` syntax, which is built-in typing, so I don't need `from typing import ...` unless I use `Optional`. I will stick to built-in generic syntax.
    Actually, to be safe and compatible with the prompt's style, I will use the syntax provided in the prompt directly.

    Re-reading: "Write only the Python code, no explanations."
    Okay.

    One consideration: The prompt example passes `priority` as a keyword argument `priority=2`. My signature `priority: int = 0` supports this.

    Let's assemble the final block.

    Wait, one detail in the requirements: "Jobs with the same priority should maintain FIFO order".
    Using a counter incremented on every add ensures that earlier jobs have smaller counter values. Since tuple comparison compares the second element if the first is equal, smaller counter comes out first. This satisfies FIFO.

    Code looks solid.

    ```python
    import heapq

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

        def add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None:
            # Negate priority to simulate max-heap behavior using heapq (min-heap)
            # Counter ensures FIFO ordering for jobs with the same priority
            heapq.heappush(self._heap, (-priority, self._counter, job_name, job_data))
            self._counter += 1

        def get_next_job(self) -> tuple[str, dict] | None:
            if not self._heap:
                return None
            _, _, job_name, job_data = heapq.heappop(self._heap)
            return (job_name, job_data)
    ```
    Wait, `tuple[str, dict]` syntax is valid in Python 3.9+. `|` is valid in 3.10+.
    I will assume Python 3.10+ based on the prompt's type hint style.

    One final check: The prompt example:
    `queue.add_job("normal", {"type": "normal"}, priority=0)`
    My code: `def add_job(self, job_name: str, job_data: dict, priority: int = 0)`
    This matches perfectly.

    I will remove comments to keep it strictly code, or keep them minimal. The instruction says "Write only the Python code". Comments are technically code, but often cleaner to have no comments if not requested. However, logic explanation inside code is often helpful. I'll keep it minimal or clean. I'll remove comments to be safe on "only code".

    Wait, `dict` vs `Dict[str, Any]`. The prompt uses `dict`. I'll use `dict`.
    The prompt uses `tuple[str, dict] | None`. I'll use that exact return type.

    Final check on imports. `heapq` is needed.

    One detail: `job_data` in the example is `{"type": "normal"}`. It's a dict.
    Okay.

    Let's write it.

</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, job_name: str, job_data: dict, priority: int = 0) -> None:
        # Negate priority to simulate max-heap behavior (higher priority first)
        # Counter ensures FIFO order for same priority jobs
        heapq.heappush(self._heap, (-priority, self._counter, job_name, job_data))
        self._counter += 1

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