<reasoning_content>
*   Task: Implement priority-based job scheduling for a queue.
    *   Requirements:
        1.  `add_job(name, metadata, priority=0)`: Add job with priority.
        2.  Higher priority processed first (2 > 1 > 0).
        3.  Tie-breaker: FIFO (First-In, First-Out) for same priority.
        4.  `get_next_job() -> tuple[str, dict] | None`: Returns the highest priority job.
    *   Priority Levels: 0 (Normal), 1 (High), 2 (Critical).
    *   Constraint: Write *only* the Python code, no explanations.

    *   A priority queue is needed.
    *   Python's `heapq` is a min-heap. To simulate a max-heap for priorities, we can store negative priority values.
    *   To handle the FIFO requirement for equal priorities, we need a sequence counter (entry count) as a secondary sort key.
    *   Tuple format for `heapq`: `(-priority, counter, (name, metadata))`.

    *   `__init__`: Initialize heap and counter.
    *   `add_job(name, metadata, priority=0)`:
        *   Increment counter.
        *   Push `(-priority, self._counter, (name, metadata))` into heap.
    *   `get_next_job()`:
        *   If heap is empty, return `None`.
        *   Pop from heap.
        *   Return the name and metadata part.

    *   `queue.add_job("normal", {"type": "normal"}, priority=0)` -> Heap: `[(0, 1, ("normal", {...}))]`
    *   `queue.add_job("critical", {"type": "critical"}, priority=2)` -> Heap: `[(-2, 2, ("critical", {...})), (0, 1, ("normal", {...}))]`
    *   `queue.add_job("high", {"type": "high"}, priority=1)` -> Heap: `[(-2, 2, ("critical", {...})), (0, 1, ("normal", {...})), (-1, 3, ("high", {...}))]`
    *   Wait, `heapq` sorts by first element, then second, etc.
    *   Values:
        1. `(-0, 1, ("normal", ...))`
        2. `(-2, 2, ("critical", ...))`
        3. `(-1, 3, ("high", ...))`
    *   Heap order after pushes:
        1. `(-2, 2, ("critical", ...))`
        2. `(-1, 3, ("high", ...))`
        3. `(0, 1, ("normal", ...))`
    *   `pop()` returns `(-2, 2, ("critical", ...))`. Correct.
    *   If two jobs have priority 2:
        *   Job A: `(-2, 10, ("A", ...))`
        *   Job B: `(-2, 11, ("B", ...))`
        *   `pop()` returns Job A. Correct (FIFO).

    ```python
    import heapq

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

        def add_job(self, name: str, metadata: dict, priority: int = 0):
            # Use negative priority for max-heap behavior
            # Use counter to ensure FIFO for same priority
            heapq.heappush(self._queue, (-priority, self._counter, (name, metadata)))
            self._counter += 1

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

    *   `add_job` accepts `priority=0`? Yes.
    *   Higher priority first? Yes (via `-priority`).
    *   FIFO for same priority? Yes (via `self._counter`).
    *   `get_next_job` return type `tuple[str, dict] | None`? Yes.

Ensure no explanations are included.
</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, name: str, metadata: dict, priority: int = 0):
        # heapq is a min-heap. To simulate a max-heap for priority, 
        # we use negative priority. The counter ensures FIFO for 
        # jobs with the same priority.
        heapq.heappush(self._queue, (-priority, self._counter, (name, metadata)))
        self._counter += 1

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