<reasoning_content>
Thinking Process:

1.  **Understand the Goal**: The user wants a Python implementation of a priority-based job scheduling queue.
2.  **Analyze Requirements**:
    *   `add_job` method: Accepts job name/ID, data, and optional `priority` (default=0).
    *   Priority logic: Higher priority number = higher priority (e.g., 2 > 1 > 0).
    *   FIFO for same priority: Jobs added first with the same priority should be processed first.
    *   `get_next_job` method: Returns the highest priority job as a tuple `(job_name, job_data)` or `None` if empty.
    *   Output: Only Python code, no explanations.

3.  **Determine Data Structure**:
    *   A standard `queue.Queue` doesn't support priority natively in a way that allows easy insertion with priority without re-queueing or complex locking.
    *   A list with sorting is inefficient for large datasets ($O(N)$ insert or $O(N)$ pop).
    *   A heap (priority queue) is the standard choice. Python's `heapq` module is a min-heap.
    *   To use a min-heap for "higher priority number = higher priority", we can negate the priority (store `-priority`) or implement a custom comparator (though `heapq` needs tuples comparable).
    *   To maintain FIFO for same priorities, we need a tie-breaker. A sequence counter (timestamp or incrementing integer) works well.
    *   Tuple structure for heap: `(-priority, sequence_number, job_name, job_data)`.
        *   `-priority`: Since it's a min-heap, smaller values come first. `-2 < -1 < -0`, so priority 2 comes before 1 comes before 0.
        *   `sequence_number`: Ensures FIFO. Smaller numbers (added earlier) come first.
        *   `job_name`/`job_data`: The payload.

4.  **Drafting the Class**:

   ```python
   import heapq

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

       def add_job(self, name: str, data: dict, priority: int = 0):
           # Negate priority because heapq is a min-heap
           # Use counter to maintain FIFO order for same priorities
           entry = [-priority, self._counter, name, data]
           self._counter += 1
           heapq.heappush(self._heap, entry)

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._heap:
               return None
           # Pop the smallest element (highest priority, earliest added)
           priority, counter, name, data = heapq.heappop(self._heap)
           return (name, data)
   ```

5.  **Refining Types and Constraints**:
    *   The prompt asks for `get_next_job() -> tuple[str, dict] | None`.
    *   The prompt asks for `add_job` to accept `name` (implied by example `queue.add_job("normal", ...)`), `data`, and `priority`.
    *   Check example usage: `queue.add_job("normal", {"type": "normal"}, priority=0)`.
    *   Wait, the example shows `add_job("normal", ...)` where "normal" looks like a name/ID. The return type of `get_next_job` is `tuple[str, dict]`, implying the first element is a string (name) and second is dict (data).
    *   Let's check the example logic again.
        `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.
    *   My draft looks consistent with this.

6.  **Edge Cases**:
    *   Empty queue: `get_next_job` returns `None`. Handled.
    *   Same priority: Handled by `_counter`.

7.  **Final Code Structure**:
    *   Import `heapq`.
    *   Define `JobQueue` class.
    *   Implement `__init__`, `add_job`, `get_next_job`.

8.  **Alternative without `heapq` (if external imports are discouraged, though usually standard lib is fine)**:
    *   Using a list and `sort` or `insert`.
    *   `insert` in middle of list is $O(N)$. `heappush` is $O(\log N)$. `heapq` is the correct engineering choice.
    *   However, sometimes simple interview questions prefer a list with manual sorting if the dataset is tiny. But "Implement priority-based job scheduling" usually implies a proper structure. I will stick to `heapq` as it's the standard Pythonic way. If strict "no imports" isn't specified, `heapq` is best. If I must avoid imports, I can use a list and `bisect` or just `insert` with a key, but `heapq` is robust.
    *   Let's check if I can do it with just a list and sorting.
        `self.jobs = []`
        `add_job`: append.
        `get_next_job`: sort by `(-priority, insertion_index)`, pop first.
        Sorting every time is $O(N \log N)$. Heap is $O(\log N)$ push, $O(\log N)$ pop.
        I'll use `heapq`.

    *   Wait, is `heapq` allowed? The prompt doesn't restrict imports. It's standard library.
    *   However, to be absolutely safe and dependency-free (just in case), a list with a counter is easy to implement manually, but `heapq` is better. I'll stick to `heapq` as it's the correct tool. *Self-correction*: Actually, writing a custom heap or just using a list is trivial, but `heapq` is standard. I will use `heapq`.

    *   *Self-Correction on imports*: Sometimes these prompts are for environments where you can't import. But usually, standard libs are fine. Let's look at the complexity. A list `insert` based approach:
        ```python
        class JobQueue:
            def __init__(self):
                self.jobs = [] # List of (-priority, counter, name, data)
                self.counter = 0

            def add_job(self, name, data, priority=0):
                self.jobs.append((-priority, self.counter, name, data))
                self.counter += 1
                # To keep it sorted without heap operations for every add (which is O(N log N) sort vs O(N) heapify? No, heap push is log N)
                # Actually, if we just append and sort on pop, it's slow.
                # If we insert in order, it's O(N).
                # Heap is best.
        ```
    *   I will use `heapq`.

    *   *Refinement*: The prompt asks for "tuple[str, dict]". My heap stores `name` (str) and `data` (dict). That matches.

    *   Let's double check the `get_next_job` return type hint syntax. `tuple[str, dict] | None` is Python 3.10+ syntax. I should ensure the code is compatible or just use the hint as requested. The prompt uses it, so I will use it.

    *   Wait, looking at the code I drafted:
        `entry = [-priority, self._counter, name, data]`
        If `name` or `data` are not comparable (e.g. if `name` isn't a string? Prompt says `tuple[str, dict]`, so name is str), it's fine. Strings are comparable.
        Actually, `heapq` compares tuples element by element.
        1. `-priority` (int)
        2. `self._counter` (int)
        3. `name` (str) - *Wait*, if priorities and counters are equal (impossible for counter), it compares name. That's fine.
        4. `data` (dict) - *Problem*. Dicts are not comparable in Python 3 (`TypeError: '<' not supported between instances of 'dict' and 'dict'`).
        *Fix*: The tuple in the heap must not contain the dict at a position where it might be compared.
        Since `name` is unique? Not necessarily. But `counter` is unique.
        So the tuple is `(-priority, counter, name, data)`.
        Comparison logic:
        1. Compare `-priority`. If different, result determined.
        2. If same, compare `counter`. Since `counter` is unique and strictly increasing, the result is determined here. `data` is never compared because `counter` breaks the tie before reaching `data`.
        *Wait*, `counter` is unique per job. So `data` will never be compared.
        *However*, if I had duplicate counters (bug), it would crash. But I increment it.
        *Actually*, to be safe and clean, usually people put the payload at the end or use a wrapper. But strictly speaking, with a unique counter, it works.
        *But*, what if I don't use a counter and rely on insertion order? Python lists don't track insertion order index easily for sorting unless stored.
        So `(-priority, counter, name, data)` is safe because `counter` is unique.

    *   Let's verify the "FIFO" requirement.
        Job A: priority 0, counter 0. Tuple: `(0, 0, "A", data)`
        Job B: priority 0, counter 1. Tuple: `(0, 1, "B", data)`
        Heap pop: `(0, 0, ...)` comes before `(0, 1, ...)`. Correct.
        Job C: priority 1, counter 2. Tuple: `(-1, 2, "C", data)`.
        Heap pop: `(-1, ...)` comes before `(0, ...)`. Correct (since -1 < 0).

    *   Wait, `priority` 2 (Critical) vs `priority` 0 (Normal).
        Normal: priority 0 -> stored as 0.
        Critical: priority 2 -> stored as -2.
        Min-heap pops smallest. -2 < 0. So Critical pops first. Correct.

    *   One detail: The prompt asks for `add_job` to accept `name`?
        Example: `queue.add_job("normal", {"type": "normal"}, priority=0)`
        Arguments: `name` (str), `data` (dict), `priority` (int, kwarg).
        My signature: `def add_job(self, name: str, data: dict, priority: int = 0):`
        Matches.

    *   One detail: `get_next_job` returns `tuple[str, dict] | None`.
        My return: `return (name, data)`.
        Matches.

    *   One detail: "Write only the Python code".

    *   Let's check if `heapq` is allowed. If not, I can implement a simple list-based priority queue.
        List based:
        `self.jobs = []`
        `add_job`: append.
        `get_next_job`:
           If empty, return None.
           Find index of max priority (min -priority), then min counter.
           Pop and return.
        This is $O(N)$ per operation. Acceptable for small scripts, but $O(\log N)$ is better.
        Given the prompt is generic, standard library is usually expected. But to be 100% robust and "implementation" focused (sometimes interviewers want you to build the heap or use a list), I might just use a list and `sort` or `min`?
        Actually, using `heapq` is the most professional answer. I'll stick with it. But wait, if the environment doesn't allow imports?
        Let's look at the complexity of a list implementation.
        ```python
        class JobQueue:
            def __init__(self):
                self._jobs = [] # List of tuples: (priority, counter, name, data)

            def add_job(self, name: str, data: dict, priority: int = 0):
                # Store negative priority for max-heap behavior with min-heap logic or just handle sorting
                # Let's store (priority, counter, name, data) and sort descending on priority?
                # Or just keep list unsorted and find max on pop.
                self._jobs.append((priority, len(self._jobs), name, data))

            def get_next_job(self) -> tuple[str, dict] | None:
                if not self._jobs:
                    return None
                # Find job with highest priority, then lowest counter (FIFO)
                # We want max(priority), min(counter).
                # Sort key: (-priority, counter)
                self._jobs.sort(key=lambda x: (-x[0], x[1]))
                _, _, name, data = self._jobs.pop(0)
                return (name, data)
        ```
        Sorting every time is inefficient.
        However, `heapq` is built-in. It is the correct answer. I will use `heapq`.

    *   Wait, is there any ambiguity in "tuple[str, dict] | None"?
        It's type hinting. I should include it in the function definition.

    *   Let's refine the code to be clean.

```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 store (-priority, counter, name, data)
        # Negating priority because heapq is a min-heap, but we want higher priority numbers first.
        # Counter ensures FIFO for same priorities.
        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
        # Pop the item with the smallest tuple value (highest priority, earliest added)
        _, _, name, data = heapq.heappop(self._queue)
        return (name, data)
```

    *   Wait, the prompt didn't explicitly say I can import `heapq`. "Implement priority-based job scheduling". Sometimes this implies writing the logic. But `heapq` is standard.
    *   However, to be safe against "no imports" constraints often found in these text prompts, I can implement a simple heap or just use a list if performance isn't the primary constraint (usually it's logic).
    *   But `heapq` is the standard way to do priority queues in Python.
    *   Let's consider if I should provide a list-based solution to be dependency-free.
    *   List based solution with `insert`:
        ```python
        class JobQueue:
            def __init__(self):
                self._jobs = [] # Stores tuples (priority, counter, name, data)
                self._counter = 0

            def add_job(self, name: str, data: dict, priority: int = 0):
                # We want higher priority first.
                # If we use a list and insert in sorted order:
                # Key for sorting: priority (desc), counter (asc)
                # To insert efficiently, we can just append and sort later, or bisect.
                # But bisect works on 1D arrays.
                # Simplest dependency-free way:
                self._jobs.append((priority, self._counter, name, data))
                self._counter += 1
                # Sort to maintain order? O(N log N) per add.
                # Or O(N) insert.
                
            def get_next_job(self) -> tuple[str, dict] | None:
                if not self._jobs:
                    return None
                # Find max priority, then min counter
                # Using max with key
                best_idx = max(range(len(self._jobs)), key=lambda i: (self._jobs[i][0], -self._jobs[i][1]))
                # Wait, max priority is higher number. 
                # If priorities equal, we want smaller counter (FIFO).
                # Key for max: (priority, -counter)
                best_idx = max(range(len(self._jobs)), key=lambda i: (self._jobs[i][0], -self._jobs[i][1]))
                
                _, _, name, data = self._jobs.pop(best_idx)
                return (name, data)
        ```
        This is $O(N)$ for add (if we don't sort) and $O(N)$ for get.
        Actually, if we just append to list and find max on get, add is $O(1)$, get is $O(N)$.
        If we sort on add, add is $O(N)$, get is $O(1)$ (pop front).
        Given "scheduling", usually adds happen, then gets happen, or mixed.
        The heap solution is $O(\log N)$ for both. It is superior.
        I will stick with `heapq` as it is the Pythonic standard. If the user wanted a raw algorithm implementation, they usually specify "without using libraries" or "implement a heap".

    *   Wait, checking the prompt again: "Implement priority-based job scheduling".
    *   It's a coding task. Using standard library is acceptable.
    *   However, looking at the provided example, it's very simple.
    *   Let's check if there's any tricky requirement.
    *   "Jobs with the same priority should maintain FIFO order".
    *   My counter handles this.
    *   "Higher priority jobs should be processed before lower priority jobs".
    *   My negated priority handles this.
    *   "default=0".
    *   Handled.

    *   Let's write the code cleanly.

    *   *Self-Correction*: Is `tuple[str, dict] | None` valid syntax in all Python versions? It requires Python 3.10. The prompt uses it, so the environment supports it.

    *   One minor optimization: The `name` and `data` in the heap tuple. Since `counter` is unique, `name` and `data` don't affect ordering. But they must be comparable if `counter` wasn't unique? No, tuple comparison stops at first difference. Since `counter` is unique, it never reaches `name` or `data`. So it's safe even if `data` is a dict.

    *   Let's refine the variable names for clarity.

```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # Store as (-priority, counter, name, data)
        # heapq is a min-heap, so negating priority makes higher priority numbers come first.
        # Counter ensures FIFO order for same priorities.
        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
        # Pop the highest priority job (smallest negative priority, smallest counter)
        _, _, name, data = heapq.heappop(self._heap)
        return (name, data)
```
    *   Wait, is it possible to have `add_job` called with just positional args? `queue.add_job("normal", {"type": "normal"}, priority=0)`.
    *   My signature: `def add_job(self, name: str, data: dict, priority: int = 0):`.
    *   "normal" -> name.
    *   {"type": "normal"} -> data.
    *   priority=0 -> priority.
    *   Matches perfectly.

    *   What if the user passes priority as positional? `queue.add_job("normal", {"type": "normal"}, 0)`.
    *   My signature allows it.
    *   What if priority is 1? `queue.add_job("high", {"type": "high"}, 1)`.
    *   Works.

    *   Is there any constraint on `name` being unique? Not specified. Even if not unique, counter handles ordering.
    *   Is there any constraint on `data`? No.

    *   Let's consider if I should avoid `heapq` just in case.
    *   If I write a custom class that acts as a queue, it might be safer for a generic "implement" request.
    *   But `heapq` is the tool for the job.
    *   I'll provide the `heapq` version. It's concise and correct.

    *   Wait, I should check if the prompt implies a specific class name. No, just "Implement...". I'll name it `JobQueue`.

    *   Let's check the imports. `import heapq` is at the top.
    *   The prompt asks for "Write only the Python code".

    *   One thought: Maybe the user wants a solution without imports to demonstrate algorithmic knowledge?
    *   If I were to do it without imports:
    *   Using a list and `sort` or `insert`.
    *   `insert` is $O(N)$. `sort` is $O(N \log N)$.
    *   With a counter, we can just append and find max on pop.
    *   Or, since it's a "queue", maybe it's a stream?
    *   Let's stick to `heapq`. It's standard.

    *   Wait, if I use `heapq`, I need to import it.
    *   If the user copies this into a file, they need the import.
    *   I will include the import.

    *   Let's check the return type of `get_next_job` again. `tuple[str, dict] | None`.
    *   My code returns `(name, data)`. `name` is str, `data` is dict. Correct.

    *   Let's double check the "Higher priority jobs should be processed before lower priority jobs".
    *   Priority 2 (Critical) > Priority 1 (High) > Priority 0 (Normal).
    *   My code: stores `-2`, `-1`, `0`.
    *   Heap pops smallest. `-2` is smallest. So 2 comes out first. Correct.

    *   "Jobs with the same priority should maintain FIFO order".
    *   Priority 0 jobs.
    *   Job A (added first): counter 0. Tuple `(0, 0, ...)`
    *   Job B (added second): counter 1. Tuple `(0, 1, ...)`
    *   Heap pops `(0, 0)` before `(0, 1)`. Correct.

    *   Final check on code style.
    *   Type hints included.
    *   Comments explaining logic (optional but good practice, though prompt says "no explanations", comments inside code are usually fine, but I'll keep them minimal or remove them to be safe? "Write only the Python code, no explanations" usually refers to the output text outside the code block. Comments inside are part of code. I'll include brief comments for clarity).

    *   Actually, I'll remove comments to be strictly "code only" if interpretation is strict, but usually comments are fine. I'll keep them minimal.

    *   Wait, looking at the example again.
    *   `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()`
    *   The example output comment says `# Returns critical job first`.
    *   My logic holds.

    *   Let's write the final block.

```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # Use negative priority for max-heap behavior with min-heap implementation
        # Use counter to maintain FIFO order for same priorities
        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
        # Pop the item with highest priority (lowest negative priority value)
        # and earliest insertion time (lowest counter)
        _, _, name, data = heapq.heappop(self._heap)
        return (name, data)
```
    *   Is `heapq` guaranteed to be available? Yes, standard library.
    *   Is the syntax `tuple[str, dict] | None` valid? Yes, Python 3.10+.
    *   If the environment is older (3.9 or lower), it would fail. But the prompt used that syntax, so I assume 3.10+.
    *   If I want to be safe for 3.9, I'd use `typing.Tuple` and `Optional`. But I should match the prompt's style.

    *   One detail: The prompt example uses `priority=0` explicitly in the first call, but says default is 0.
    *   My code handles default.

    *   One edge case: `add_job` arguments order.
    *   Prompt: `add_job("normal", {"type": "normal"}, priority=0)`
    *   My def: `add_job(self, name: str, data: dict, priority: int = 0)`
    *   Matches.

    *   What if `name` is not provided? The prompt implies it's required (positional).
    *   What if `data` is not provided? Prompt implies it's required.
    *   Seems solid.

    *   Let's check if there is any ambiguity about "tuple[str, dict]".
    *   Maybe the return should be `(name, priority, data)`?
    *   Prompt: `get_next_job() -> tuple[str, dict] | None`.
    *   It specifies exactly two elements: string and dict.
    *   My return `(name, data)` fits.

    *   Final check: "Write only the Python code, no explanations."
    *   I will output the code block.

```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # Store as (-priority, counter, name, data)
        # Negating priority ensures higher numbers are popped first (min-heap)
        # Counter ensures FIFO order for equal priorities
        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
        # Pop the highest priority job
        _, _, name, data = heapq.heappop(self._heap)
        return (name, data)
```
    *   Wait, I should check if I need to handle the case where `data` is not a dict? The type hint says `dict`. I assume valid input.
    *   Also, `name` is `str`.
    *   Looks good.

    *   Alternative: Maybe the user doesn't want `heapq` imported?
    *   If I write a pure Python list implementation, it's safer for "implement" requests that might be testing basic data structures.
    *   Let's think if a list implementation is significantly harder.
    *   List implementation:
        ```python
        class JobQueue:
            def __init__(self):
                self._jobs = [] # List of (priority, counter, name, data)
                self._counter = 0

            def add_job(self, name: str, data: dict, priority: int = 0):
                self._jobs.append((priority, self._counter, name, data))
                self._counter += 1

            def get_next_job(self) -> tuple[str, dict] | None:
                if not self._jobs:
                    return None
                # Find job with highest priority, then lowest counter
                # We can sort the list or find the max index.
                # Sorting is O(N log N). Finding max is O(N).
                # Since we remove the item, we can just find max and pop.
                
                best_idx = -1
                best_priority = -1
                best_counter = float('inf')
                
                # Linear scan to find best job
                for i, (pri, cnt, name, data) in enumerate(self._jobs):
                    if pri > best_priority or (pri == best_priority and cnt < best_counter):
                        best_priority = pri
                        best_counter = cnt
                        best_idx = i
                
                _, _, name, data = self._jobs.pop(best_idx)
                return (name, data)
        ```
    *   This is $O(N)$ per operation. `heapq` is $O(\log N)$.
    *   For a job queue, $O(\log N)$ is preferred.
    *   However, if $N$ is small, it doesn't matter.
    *   But `heapq` is the "correct" Pythonic way. I will stick with `heapq`. It shows knowledge of standard libraries.

    *   Wait, is `heapq` allowed in the specific context? The prompt is generic.
    *   I'll provide the `heapq` solution.

    *   Wait, checking the prompt requirements again.
    *   "Implement priority-based job scheduling for the queue."
    *   It doesn't say "using a heap".
    *   But it's the best way.

    *   I'll stick to the `heapq` solution.

    *   Wait, I notice the prompt example:
    *   `queue.add_job("normal", {"type": "normal"}, priority=0)`
    *   `queue.add_job("critical", {"type": "critical"}, priority=2)`
    *   `queue.add_job("high", {"type": "high"}, priority=1)`
    *   If I run my code:
    *   1. `add_job("normal", ..., 0)` -> heap: `[(0, 0, "normal", ...)]`
    *   2. `add_job("critical", ..., 2)` -> heap: `[(-2, 1, "critical", ...), (0, 0, "normal", ...)]` (after push/sift)
    *   3. `add_job("high", ..., 1)` -> heap: `[(-2, 1, "critical", ...), (0, 0, "normal", ...), (-1, 2, "high", ...)]` -> sifting might rearrange, but top is -2.
    *   `get_next_job` -> pops `(-2, 1, "critical", ...)`. Returns `("critical", {"type": "critical"})`.
    *   Correct.

    *   What if priorities are same?
    *   `add_job("A", ..., 0)` -> `(0, 0, "A", ...)`
    *   `add_job("B", ..., 0)` -> `(0, 1, "B", ...)`
    *   Pop -> `(0, 0, "A", ...)` comes first.
    *   Correct.

    *   Final check on code.
    *   I will output the code now.

```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # Store as (-priority, counter, name, data)
        # Negating priority because heapq is a min-heap, so smaller values come first.
        # Higher priority number (e.g., 2) becomes -2, which is smaller than -1 or 0.
        # Counter ensures FIFO order for jobs with the 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
        # Pop the job with the highest priority (smallest negative priority)
        # and earliest insertion time (smallest counter).
        _, _, name, data = heapq.heappop(self._heap)
        return (name, data)
```
    *   Wait, I should check if I need to handle `None` return type hint properly if Python version < 3.10. But prompt used it.
    *   I'll just provide the code.

    *   Wait, the prompt says "Write only the Python code".
    *   I will provide the code block.

    *   One detail: The prompt example uses `queue = JobQueue()`.
    *   My class is `JobQueue`.
    *   Everything aligns.

    *   One last check: Does `add_job` need to return anything? No.
    *   Does `get_next_job` need to remove the job? Yes, "get" usually implies consumption in a queue context, especially with "scheduling". If it was peek, it would be `peek`. "Get next job" implies processing it, so it should be removed. My implementation removes it (`heappop`).

    *   Ready.

</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, name: str, data: dict, priority: int = 0):
        # Store as (-priority, counter, name, data)
        # Negating priority because heapq is a min-heap, so smaller values come first.
        # Higher priority number (e.g., 2) becomes -2, which is smaller than -1 or 0.
        # Counter ensures FIFO order for jobs with the 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
        # Pop the job with the highest priority (smallest negative priority)
        # and earliest insertion time (smallest counter).
        _, _, name, data = heapq.heappop(self._heap)
        return (name, data)
```
</content>