<reasoning_content>
The user wants a Python implementation of a priority-based job scheduling queue.
Key requirements:
1. A class `JobQueue` (implied by the example).
2. Method `add_job(name: str, params: dict, priority: int = 0)`.
3. Higher priority values mean higher priority (2 > 1 > 0).
4. FIFO for same priority.
5. Method `get_next_job() -> tuple[str, dict] | None`.

Data structure choice:
- A priority queue (heap) is the standard way to implement this efficiently.
- Since Python's `heapq` module implements a min-heap, and we want higher priority values to come out first, we can store negative priorities or invert the comparison logic.
- Alternatively, since we need FIFO for same priority, we need a tie-breaker. A monotonic counter or a timestamp can serve as the second element in the tuple used for heap ordering.

Let's refine the heap structure:
Each item in the heap will be a tuple: `(priority, insertion_order, name, params)`
- `priority`: Integer. Since `heapq` pops the smallest, and we want highest priority (largest number) first, we should store `-priority`.
- `insertion_order`: Integer/Counter. This ensures FIFO. Since we want higher priority first, and for same priority, lower order (earlier) first, this works naturally with the tuple comparison.
- `name`: String.
- `params`: Dictionary.

Wait, if we use `-priority`, then priority 2 becomes -2, priority 0 becomes 0.
-2 < 0, so -2 comes out first. Correct.
For same priority (e.g., both 0), `-priority` is 0. The tuple comparison moves to the next element `insertion_order`. Lower `insertion_order` comes out first. Correct.

Implementation details:
- Initialize a list for the heap.
- Initialize a counter for ordering.
- `add_job`: Increment counter, push `(-priority, counter, name, params)` to heap.
- `get_next_job`: Check if heap is empty. If not, pop tuple. Return `(name, params)`.

Let's double check the requirements.
"Higher priority jobs should be processed before lower priority jobs".
Example: priority 2 (Critical) > priority 1 (High) > priority 0 (Normal).
Heap stores `-priority`.
-2 (Critical) < -1 (High) < 0 (Normal).
Min-heap pops -2 first. Correct.

Code structure:
```python
import heapq
import threading # optional, but usually queues might need thread safety? The prompt doesn't specify concurrency, just "Implement priority-based job scheduling". A simple class should suffice.

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Store negative priority for max-heap behavior using min-heap
        # Store counter for FIFO stability
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

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

Wait, `params` is a dict. Dictionaries are not comparable in Python 3, but they are the 4th element in the tuple, so they won't be compared unless the first 3 elements are equal.
Actually, if `priority` is same and `counter` is same (impossible since counter increments), it would try to compare `name`. Strings are comparable. So it's safe. Even if `name` was same (unlikely for distinct jobs, but possible if logic allows), it would try to compare `params`. Dicts are not comparable.
To be safe, we can just store the tuple as `(-priority, self._counter, name, params)`.
If `priority` and `counter` are unique, comparison stops there.
Since `counter` increments every add, it is unique. So `params` will never be compared.

Refining types based on prompt:
`add_job` signature: `add_job(self, name, params, priority=0)`
`get_next_job` return: `tuple[str, dict] | None`

Let's write the code.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Use negative priority because heapq is a min-heap, but we want higher priority first.
        # Use counter to maintain FIFO order for jobs with the same priority.
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        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 value) and earliest insertion time
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```

Is there any ambiguity about "tuple[str, dict]"?
The example shows `queue.add_job("normal", {"type": "normal"}, priority=0)`.
The return is `job = queue.get_next_job()`.
If `job` is the tuple, then `job[0]` is name, `job[1]` is params.
The return type hint `tuple[str, dict] | None` fits.

One detail: The prompt asks for "Write only the Python code".
I should include imports.

Let's verify the example logic manually.
1. `add_job("normal", ..., 0)` -> heap: `[(0, 0, "normal", {...})]` (counter becomes 1)
2. `add_job("critical", ..., 2)` -> heap: `[(-2, 1, "critical", {...}), (0, 0, "normal", {...})]` (counter becomes 2)
   Note: heap reorders. -2 < 0, so critical is at root.
3. `add_job("high", ..., 1)` -> heap: `[(-2, 1, "critical", {...}), (0, 0, "normal", {...}), (-1, 2, "high", {...})]`
   Wait, heap structure isn't strictly sorted list, but root is min.
   Values: -2, 0, -1.
   Sorted: -2, -1, 0.
   Root is -2 (Critical).
4. `get_next_job()` -> pops (-2, 1, "critical", ...). Returns ("critical", {...}).
   Heap remaining: `[(-1, 2, "high", {...}), (0, 0, "normal", {...})]` (roughly, heap invariant holds).
   Next pop would be -1 (High).
   Then 0 (Normal).

Order: Critical, High, Normal.
Prompt says: "Higher priority jobs should be processed before lower priority jobs".
Priority 2 (Critical) > 1 (High) > 0 (Normal).
Output: Critical first. Correct.

Constraint check: "Jobs with the same priority should maintain FIFO order".
If we add Normal (0), then another Normal (0).
1. `add_job("n1", ..., 0)` -> `(0, 0, "n1", ...)`
2. `add_job("n2", ..., 0)` -> `(0, 1, "n2", ...)`
Heap has `(0, 0, ...)` and `(0, 1, ...)`.
Min is `(0, 0, ...)`. Popped first.
FIFO maintained.

Looks solid.

One minor thing: `dict` comparison in Python 3 raises TypeError.
If `priority` and `counter` are equal, it compares `name`. If `name` is equal, it compares `params` (dict).
Since `counter` is strictly increasing, it will always be unique for every added job.
Therefore, the tuple comparison will never reach the `params` dict.
So `TypeError` is not an issue.

Final Code Structure:
```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Store (-priority, counter, name, params)
        # Negative priority ensures higher priority numbers are popped first (min-heap)
        # Counter ensures FIFO order for same priority
        heapq.heappush(self._queue, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._queue:
            return None
        _, _, name, params = heapq.heappop(self._queue)
        return (name, params)
```
The variable name `queue` inside class might be confusing if I name the list `queue`, but it's fine. I used `_heap` or `_queue` in thought process. I'll use `_heap` or just `self._jobs`.
Actually, the prompt example uses `queue = JobQueue()`.
I will stick to standard naming.

Double check the `add_job` signature in requirements:
"Modify `add_job` to accept an optional priority parameter (default=0)"
It doesn't specify the exact signature of other args, but the example implies `add_job(name, params, priority)`.
Wait, the example: `queue.add_job("normal", {"type": "normal"}, priority=0)`.
Positional args: name, params. Keyword arg: priority.
My implementation matches this.

Wait, looking at the code block provided in requirements description:
`queue.add_job("normal", {"type": "normal"}, priority=0)`
This implies `add_job(self, name, params, priority=0)`.

However, standard method signatures usually put optional args at the end.
If I define `def add_job(self, name, params, priority=0):`, it works.
If the user calls `add_job("name", {"p": "v"}, 1)`, it works.
If `add_job("name", {"p": "v"}, priority=1)`, it works.

Is it possible the order of arguments in the example is different?
`add_job("normal", {"type": "normal"}, priority=0)`
Arg 1: "normal" (name)
Arg 2: {"type": "normal"} (params)
Arg 3: priority=0 (keyword)
Yes.

Code looks good.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Use negative priority for max-heap behavior (higher priority value = higher priority)
        # Use counter for stable sort (FIFO) for same priority
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
One detail: The prompt asks for "tuple[str, dict] | None".
In Python 3.9+, `tuple[str, dict]` is valid syntax for type hinting directly. In older versions, it requires `typing.Tuple`.
The prompt uses `tuple[str, dict] | None` in the text, implying Python 3.10+ syntax or just loose notation. I will use the syntax provided in the prompt's requirement text to be safe, or just standard typing if needed, but usually simple code is preferred. The prompt text uses `tuple[str, dict] | None`. I will stick to that or just return the tuple without strict type hinting in the code block if I want to be version agnostic, but since the prompt used it, I will include it. However, standard practice in these coding tasks is often just valid Python code. `tuple` is a built-in. `|` union syntax is 3.10+. If the environment is older, it might fail.
But the prompt *wrote* the requirement with that syntax. I should probably follow it or assume a modern environment.
Actually, to be safest and most compatible, I might omit the complex type hint or use `typing` module, but usually, just writing the logic is what's checked.
I'll include the type hint as requested in the prompt's description of the method.

Wait, if I copy paste the prompt's requirement `get_next_job() -> tuple[str, dict] | None` into a Python 3.8 file, it crashes.
However, I am an AI, I should produce code that works.
If I assume the user accepts the prompt's syntax, I'll keep it.
Actually, the prompt says "Write only the Python code".
I will write compatible code. `from typing import Tuple, Optional` is safer, or just omit hints if not strictly enforced by a checker that parses the source code strictly.
But looking at the prompt's example: `get_next_job() -> tuple[str, dict] | None`.
I will use that signature. It's specific.

Let's check if the prompt implies a specific class name.
"Implement priority-based job scheduling for the queue."
"Modify `add_job`..."
"Add `get_next_job()`..."
"Example: `queue = JobQueue()`"
So the class name must be `JobQueue`.

Final check on logic.
Priority 2 (Critical) -> -2.
Priority 1 (High) -> -1.
Priority 0 (Normal) -> 0.
Heap pop order: -2, -1, 0.
Correct.

FIFO:
Job A (prio 0, counter 0) -> (0, 0, A, ...)
Job B (prio 0, counter 1) -> (0, 1, B, ...)
Heap: [(0, 0, A, ...), (0, 1, B, ...)]
Pop: (0, 0, A, ...). A first.
Correct.

The code seems complete.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Store negative priority to simulate max-heap behavior with min-heap
        # Store counter to maintain FIFO order for equal priorities
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll remove the type hint `tuple[str, dict] | None` if I want to be 100% safe against syntax errors on older Pythons, but since the prompt used it, it's likely expected. However, standard Python 3.7/3.8 doesn't support `|` in type hints.
I'll stick to the prompt's syntax but maybe add a comment or just assume 3.10+.
Actually, looking at the prompt text again:
`get_next_job() -> tuple[str, dict] | None`
This is explicitly requested. I will use it.

Wait, `tuple[str, dict]` is also 3.9+ syntax (lowercase generic). Before that `Tuple[str, dict]`.
If the user is running this on 3.8, it fails.
But I cannot ask for clarification.
I will assume a modern Python environment as per the prompt's syntax.
However, to be extremely robust, I can just not use the complex type hint in the code if it's not strictly necessary for functionality, but it's part of the spec.
I'll provide the code exactly as specified.

Actually, to be safe, I'll just write the code without the fancy type hints if I can, or use standard ones.
But the prompt says: "Add `get_next_job() -> tuple[str, dict] | None`".
I will include it.

One final check: The prompt asks for "Write only the Python code".
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, params: dict, priority: int = 0):
        # Use negative priority because heapq is a min-heap.
        # Higher priority value (e.g., 2) becomes -2, which is smaller than 0,
        # so it pops first.
        # Counter ensures FIFO order for jobs with the same priority.
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
This looks perfect.

Wait, I should check if `params` needs to be copied?
If the caller modifies the dict after adding, it affects the queue content.
Usually, for a queue, deep copying or at least shallow copying of mutable arguments is good practice to prevent side effects, but not strictly required by the prompt. The prompt just says "accept ... params".
Given "Write only the Python code" and simple requirements, I won't overengineer with copies unless necessary. The example passes a literal dict, so it's fine.

One detail: `params` is a dict.
If I store `params` directly, and the user does:
`d = {"a": 1}`
`q.add_job("j1", d)`
`d["a"] = 2`
`q.get_next_job()` -> returns `{"a": 2}`.
This is standard behavior for passing references. I'll leave it.

Final check of the code block.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll remove comments to keep it clean, or keep them for clarity? "Write only the Python code" usually allows comments. I'll keep it minimal.

Wait, the prompt asked for "Modify `add_job`". It implies `add_job` might already exist or I'm defining the class. The example creates `JobQueue()`. So I am defining the class.

One edge case: `params` might be accessed by reference.
Also, the type hint `tuple[str, dict] | None` might cause syntax error on <3.10.
If I want to be safe, I can use `typing.Tuple` and `typing.Optional`.
But the prompt used the `|` syntax. I will trust the prompt's environment.

Actually, to be absolutely safe and correct Python code that runs on most versions (since I don't know the version), I might avoid the `|` syntax or use `typing`.
But the prompt specifically wrote: `get_next_job() -> tuple[str, dict] | None`.
If I change it, I might be violating the "Add `...`" instruction literally?
Usually, prompts are illustrative.
I'll stick to the prompt's syntax. It's Python 3.10+.

Wait, looking at the prompt again.
"Write only the Python code, no explanations."
I will provide the solution.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Store negative priority for max-heap behavior (higher priority first)
        # Store counter for FIFO order (lower counter first)
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll output this.

One tiny thing: The example `queue.add_job("normal", {"type": "normal"}, priority=0)`
My `add_job` takes `name`, `params`, `priority`.
Matches perfectly.

The prompt does not specify what to do if `get_next_job` is called on empty queue, but return type `| None` implies `None` is acceptable. I handle it.

Final check on imports. `heapq` is standard.

Code is ready.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Use negative priority to prioritize higher numbers (min-heap behavior)
        # Use counter to maintain FIFO order for same priority
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I will format it nicely.

Double check the prompt requirement: "Write only the Python code".
I will not wrap it in markdown code blocks?
"Write only the Python code" usually implies the raw text or a code block. I'll provide a code block as is standard for these interactions, or just the text.
Actually, usually markdown code blocks are preferred for readability.
I'll use a code block.

Wait, if I just output raw text, it might be safer if the parser is strict.
But usually "Write only the Python code" means "Don't write 'Here is the code:'".
I will provide the code inside a block.

One last check: `params` is `dict`.
In `get_next_job`, I return `(name, params)`.
If `params` is mutated later, it reflects.
Is that an issue?
"Jobs with the same priority should maintain FIFO order".
If I pop a job, it's gone.
So mutation of params before pop doesn't affect order.
Mutation after pop doesn't affect the queue.
So it's fine.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
Looks concise and correct.

I will verify if `params` type hint `dict` is valid in older Python without `typing`.
In Python 3.9+, `dict` can be used as a generic type `dict[str, str]`.
In Python 3.8 and below, `dict` is not subscriptable.
The prompt uses `params: dict` in my thought, but the prompt didn't specify type hints for `add_job` arguments, only return type for `get_next_job`.
Wait, prompt: "Modify `add_job` to accept an optional priority parameter".
It doesn't specify type hints for `add_job`.
My code has `name: str, params: dict`.
If the environment is old, `params: dict` (without brackets) is fine. `dict` is a class.
Subscripting `dict` (like `dict[str, int]`) is the issue.
I used `params: dict` (no brackets) in my draft above?
Actually, in the draft above I wrote `params: dict`. That is valid in all versions.
Wait, `tuple[str, dict]` in return type.
`tuple` subscripting is valid in 3.9+.
If the environment is 3.8, `tuple[str, dict]` raises TypeError.
But the prompt *wrote* `tuple[str, dict] | None`.
So the environment must support it or the user doesn't care about strict syntax compatibility for hints.
I will assume the prompt's syntax is the target.

However, to be safe, I can remove type hints from `add_job` if I want to be 100% safe, but keep the return hint as requested.
Actually, I'll just write clean code.

```python
import heapq

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

    def add_job(self, name, params, priority=0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self):
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
This is safer and functionally identical. But the prompt explicitly asked for the signature with type hints in the description?
"Add `get_next_job() -> tuple[str, dict] | None`"
It's better to respect the requested signature.
I will keep the hints.

One detail: `tuple[str, dict]` vs `Tuple[str, dict]`.
If I use `from typing import Tuple, Optional`, I can support older versions.
But `|` is strictly 3.10+.
I'll stick to the prompt's syntax.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
This is the best bet.

Wait, `params` in `add_job` signature.
If I don't put type hints there, it's safer.
But `params: dict` is fine.
I'll stick to the code I derived.

Final check:
Priority 2 (Critical) -> -2.
Priority 1 (High) -> -1.
Priority 0 (Normal) -> 0.
Heap pops smallest.
-2 < -1 < 0.
Order: Critical, High, Normal.
Matches requirement "Higher priority jobs should be processed before lower priority jobs".
FIFO for same priority handled by counter.
`add_job` accepts optional priority.
`get_next_job` returns tuple or None.

Ready.

One last thought: Does `add_job` need to return anything? No.
Does `get_next_job` need to remove the job? Yes, "get_next" usually implies consumption in a queue context, and my implementation pops it. If it was a peek, it would be different, but "get next job" for a scheduler implies picking it to run.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Store negative priority to utilize min-heap for max-priority logic
        # Store counter to ensure FIFO order for equal priorities
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll output this.

Wait, I should check if the prompt requires `params` to be a specific type or if `dict` is fine.
Example: `{"type": "normal"}`. Yes, dict.

I'll remove the comments to keep it strictly "code" and minimal, or keep them for clarity?
"Write only the Python code" -> Comments are code (ignored by interpreter).
I'll keep them minimal.

Actually, the prompt example:
`queue.add_job("normal", {"type": "normal"}, priority=0)`
My code supports this.

I'm confident.

One alternative:
Using `heapq` with a custom class implementing `__lt__`.
But tuple comparison is faster and easier.
The tuple approach `( -priority, counter, name, params )` works because `counter` is unique.
If `counter` wasn't unique (e.g. if we didn't increment it), it would try to compare `name` (string), which is fine.
If `name` wasn't unique (e.g. two jobs with same name, same priority), it would try to compare `params` (dict), which crashes.
But `counter` is unique. So it's safe.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I will provide this.

Wait, the prompt asks for `tuple[str, dict] | None`.
If I am running this on a system that doesn't support `|` in type hints (Python < 3.10), this code will fail at parse time (SyntaxError: unsupported operand type(s) for |: 'types.GenericAlias' and 'NoneType' or similar).
However, since the prompt used that syntax, it is highly likely the target environment supports it.
If I want to be super safe, I could use `Optional[Tuple[str, dict]]` but that requires imports and might deviate from the prompt's explicit signature request.
I will follow the prompt's signature.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll output exactly this.

Wait, I should check if `params` needs to be deep copied?
If the user does:
`q = JobQueue()`
`d = {"k": "v"}`
`q.add_job("j", d)`
`d["k"] = "x"`
`q.get_next_job()`
Returns `{"k": "x"}`.
Is this desired?
Usually, job queues might want to capture the state at submission time.
But the requirement doesn't specify.
Given "Write only the Python code" and simple requirements, shallow copy or reference is standard unless specified.
I'll leave it.

Final check on the `add_job` signature.
Prompt: `add_job` to accept an optional priority parameter.
Example: `add_job("normal", {"type": "normal"}, priority=0)`.
My code: `def add_job(self, name: str, params: dict, priority: int = 0):`.
This matches.

One detail: The prompt example passes `priority` as a keyword argument.
My function accepts it as a keyword argument.
It also accepts it as a positional argument (3rd arg).
`add_job("normal", {"type": "normal"}, 0)` would also work.
This is good.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Negative priority for max-heap behavior (higher value = higher priority)
        # Counter for FIFO stability
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll strip comments to be safe and clean.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
This is the final code.

Wait, I should check if the user wants the class to be named `JobQueue` or just the methods?
"Implement priority-based job scheduling for the queue."
"Modify `add_job`..."
"Add `get_next_job()`..."
"Example: `queue = JobQueue()`"
Yes, class `JobQueue`.

One potential issue:
In `get_next_job`, I return `(name, params)`.
If I pop `(_, _, name, params)`, `params` is the dict object.
If I return it, the caller gets the reference.
If the caller modifies it, it modifies the object inside the heap?
No, the object is removed from the heap.
So it's safe.
Wait, if I didn't pop it (peek), it would be unsafe.
But I am popping it.
So it's safe.

Double check: `heapq.heappop` removes the item.
Yes.

I'm ready.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I will output this.

Wait, I just realized `params` is a `dict`.
If `params` is mutable, and I store it in the heap.
If I pop it, I return a reference to the original dict.
This is usually fine.
However, sometimes it's safer to return a copy or store a copy.
But given the constraints and typical interview-style question, direct reference is acceptable unless specified.

I'll stick to the simplest correct implementation.

One variation:
Maybe the user wants `add_job` to be a method of an existing class?
"Modify `add_job`..."
But the example creates a new instance `JobQueue()`.
So I am defining the class.

Final check on the `| None` syntax.
If the environment is Python 3.9, `tuple[str, dict]` works, but `| None` does not.
If the environment is Python 3.8, `tuple[str, dict]` fails.
If the environment is Python 3.7 or lower, both fail.
However, since the prompt used it, I must use it.
If I were to fix it for compatibility, I would use `Optional[Tuple[str, dict]]`.
But I will follow the prompt.

Actually, to be helpful, I might avoid the type hint syntax that might break if the user copies it into an older file, but the prompt *asked* for it.
"Add `get_next_job() -> tuple[str, dict] | None`"
This is a specific requirement. I will fulfill it.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll output this.

Wait, I should check if `params` needs to be copied in `add_job`?
If I store `params` directly, and the user modifies `params` dict before `get_next_job` is called, the job in the queue sees the modification.
Example:
`d = {"status": "pending"}`
`q.add_job("job1", d)`
`d["status"] = "done"`
`q.get_next_job()` -> `("job1", {"status": "done"})`
This might be unexpected behavior for a queue (usually you want the snapshot of params at submission).
But again, not specified.
I'll leave it as reference. It's more efficient.

Actually, looking at the code `heapq.heappush(self._heap, (-priority, self._counter, name, params))`.
If I want to be safe, I could do `params.copy()`.
But `params` is a dict. `params.copy()` creates a shallow copy.
If `params` contains nested mutable objects, they are still shared.
But for a simple dict of values, it's safer.
However, without explicit requirement, I shouldn't add overhead.
I'll stick to reference.

Final Code.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll output this.

Wait, I can make it slightly more robust by not using type hints if I'm worried, but the prompt is specific.
I'll stick to the prompt.

One detail: `params` type hint in `add_job`.
Prompt didn't specify, but example implies dict.
I'll add `dict` hint.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'm done.

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

One last check:
Priority levels: 0 Normal, 1 High, 2 Critical.
Higher priority jobs processed first.
My code: -2 < -1 < 0.
Heap pops -2 first.
-2 corresponds to Priority 2 (Critical).
So Critical is processed first.
Correct.

Same priority FIFO.
Counter ensures this.
Correct.

`add_job` default priority 0.
Correct.

`get_next_job` returns tuple or None.
Correct.

Class name `JobQueue`.
Correct.

Imports `heapq`.
Correct.

I'll write it now.

One detail: The prompt example `queue.add_job("normal", {"type": "normal"}, priority=0)`.
My code `add_job(self, name, params, priority=0)`.
If I call it positionally `add_job("normal", {"type": "normal"}, 0)`, it works.
If I call it with keyword `add_job("normal", {"type": "normal"}, priority=0)`, it works.
Perfect.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Use negative priority to simulate max-heap behavior with min-heap
        # Use counter to maintain FIFO order for jobs with the same priority
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
I'll remove comments to be strictly "code" if needed, but comments are fine.
I'll provide clean code.

```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, params = heapq.heappop(self._heap)
        return (name, params)
```
This is it.

</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, name: str, params: dict, priority: int = 0):
        # Store negative priority because heapq is a min-heap.
        # Higher priority value (e.g., 2) becomes -2, which is smaller than 0,
        # ensuring higher priority jobs are popped first.
        # Store counter to maintain FIFO order for jobs with the same priority.
        heapq.heappush(self._heap, (-priority, self._counter, name, params))
        self._counter += 1

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