<reasoning_content>
Thinking Process:

1.  **Analyze the Request:**
    *   Goal: Implement a basic job queue in Python.
    *   Class: `JobQueue`.
    *   Methods:
        *   `add_job(job_id: str, data: dict) -> str`: Add a job, return `job_id`.
        *   `get_result(job_id: str) -> dict | None`: Get result of completed job.
    *   Ordering: FIFO.
    *   Storage: Internal storage until processed.
    *   Output: Only Python code, no explanations.

2.  **Determine Internal Structure:**
    *   Need a queue for processing order (FIFO). `collections.deque` is ideal.
    *   Need storage for job results. A dictionary mapping `job_id` to `result` works well.
    *   Need a way to simulate "processing". Since this is a basic implementation without external threads or workers specified, I should probably simulate the processing step or expose a method to process jobs, or just assume the results are stored when `get_result` is called (lazy evaluation) or when a worker processes them.
    *   Looking at the requirements: "The queue should store jobs internally until they are processed". "Get the result of a completed job".
    *   To make it functional, I need a mechanism to mark jobs as completed and store their results. Since no specific worker process is defined, I will add a helper method `_process_jobs` or similar to simulate the work, or allow the user to manually update results. However, the most standard interpretation for a *class implementation* like this usually involves an internal worker loop or a method to simulate completion.
    *   Simpler interpretation: The `JobQueue` manages state. `add_job` stores the job. To get a result, the job must be "completed". How does it become completed?
    *   Option A: Simulate processing inside `add_job` (unlikely, adds delay).
    *   Option B: Add a `process()` method that iterates the queue and updates results.
    *   Option C: Just store the job data and `get_result` returns the data if the job is "completed". But how does the user know it's completed?
    *   Refining the requirement: "Job should be processed in FIFO". Usually, this implies a background thread or a method that advances the queue state. Given the constraints ("Write only the Python code"), I should implement a basic simulation of processing so `get_result` makes sense.
    *   Let's add a method `process_jobs()` that simulates execution. Or, I can assume the user manually sets the result.
    *   Actually, a cleaner design for a "basic job queue" without threading overhead usually involves a `process()` method that executes the stored jobs.
    *   Let's keep it simple: Store jobs in a deque. Store results in a dict. Add a method to simulate processing (pop from queue, calculate a dummy result, store in dict).
    *   Wait, the prompt says "Implement a basic job queue". It doesn't explicitly demand a `process` method, but `get_result` implies the job must have been processed.
    *   Let's implement a `process` method to simulate the work, otherwise `get_result` will always return `None` unless the user manually updates the internal state.
    *   Alternative: Just store the job. `get_result` returns the stored data? No, it says "result of a completed job".
    *   Let's add a `process` method to the class to fulfill the logic of "processing".

3.  **Drafting the Code:**
    *   Import `deque` from `collections`.
    *   Class `JobQueue`.
    *   `__init__`: Initialize `self._queue` (deque) and `self._results` (dict).
    *   `add_job`: Validate `job_id`? Store in queue. Return `job_id`.
    *   `process`: Iterate through queue, pop, simulate work (e.g., calculate hash or just mark done), store result in `self._results`.
    *   `get_result`: Check `self._results`. Return result or `None`.

    *Self-Correction on `add_job`:* The requirement says `add_job` returns `job_id`.
    *Self-Correction on `get_result`:* Returns `dict | None`.

    *Refining the "Processing" aspect:* Since the prompt doesn't specify a worker thread or an external trigger, I will add a `process_jobs` method to simulate the execution flow, otherwise the queue sits empty of results. Or, I can make the `JobQueue` act as a context where jobs are added and then "processed" via a method call.
    Let's stick to the methods requested in the prompt plus necessary internal methods to make it work.
    Actually, looking at the example:
    ```python
    queue = JobQueue()
    job_id = queue.add_job("job1", {"task": "process_data"})
    # After processing...
    result = queue.get_result("job1")
    ```
    The comment "# After processing..." implies an action needs to happen. I will add a `process()` method to the class to handle the actual work execution simulation so the example makes sense.

4.  **Finalizing Implementation Details:**
    *   Use `collections.deque` for FIFO.
    *   Use `dict` for storing results keyed by `job_id`.
    *   `add_job`: Append to deque, store data in a local dict for processing.
    *   `process`: Pop from deque, compute result (dummy), save to results dict.
    *   `get_result`: Lookup in results dict.

    *Wait, one constraint:* "Write only the Python code".
    *   I should ensure the code is complete and runnable.

5.  **Code Structure:**
    ```python
    import collections

    class JobQueue:
        def __init__(self):
            self._queue = collections.deque()
            self._results = {}
            self._jobs = {} # To store job data for processing

        def add_job(self, job_id: str, data: dict) -> str:
            self._queue.append(job_id)
            self._jobs[job_id] = data
            return job_id

        def process_jobs(self):
            while self._queue:
                job_id = self._queue.popleft()
                data = self._jobs.get(job_id)
                # Simulate processing
                self._results[job_id] = {"status": "completed", "input": data}

        def get_result(self, job_id: str) -> dict | None:
            return self._results.get(job_id)
    ```
    *Refinement:* The prompt asks for `add_job` and `get_result`. It doesn't explicitly forbid other methods, but I should focus on the requested interface. I'll include `process_jobs` to make the example valid.
    *Constraint Check:* "Write only the Python code". I should avoid markdown blocks if possible or just provide the code block. Usually, a code block is expected.
    *Constraint Check:* `job_id` uniqueness? The prompt implies `job_id` is passed in. I should probably check if it exists, but the requirement says "return job_id". I'll just accept the passed `job_id`.

    *Simplification:* To keep it strictly to the requirements while ensuring functionality:
    1. `__init__`
    2. `add_job`
    3. `get_result`
    4. (Implicitly) Need a way to populate results. I'll add a `process` method or similar logic inside `get_result`? No, `get_result` should just fetch. I will add `process` to the class definition.

    Let's write the code.

```python
import collections

class JobQueue:
    def __init__(self):
        self._queue = collections.deque()
        self._jobs = {}
        self._results = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._jobs[job_id] = data
        return job_id

    def process(self):
        while self._queue:
            job_id = self._queue.popleft()
            data = self._jobs.get(job_id, {})
            self._results[job_id] = {"status": "completed", "data": data}

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)
```
    Wait, the requirement says `get_result` returns `dict | None`.
    The prompt asks for `job_id: str, data: dict) -> str`.
    The example usage shows `job_id = queue.add_job(...)`.
    I will include the `process` method so the example works logically.

    Wait, is there a strict constraint on *only* those two methods?
    "Create a JobQueue class with the following methods..."
    Usually, this means "at least these methods". I will add `process` to make it usable.

    Double check: "Write only the Python code". I will provide the code inside a block.

    One small detail: `job_id` uniqueness isn't enforced in the requirement, but implied by "unique job_id". I won't enforce it strictly to keep it basic, just overwrite or append. FIFO order is handled by deque.

    Let's refine the `process` logic. It shouldn't be too complex. Just a placeholder.

    Final check on imports. `collections` or `deque` directly. `from collections import deque`.

    Let's write it.

```python
from collections import deque

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._job_data = {}
        self._results = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._job_data[job_id] = data
        return job_id

    def process_jobs(self):
        while self._queue:
            job_id = self._queue.popleft()
            data = self._job_data.get(job_id)
            self._results[job_id] = {"status": "completed", "input": data}

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)
```
    Wait, `get_result` signature in prompt: `get_result(job_id: str) -> dict | None`.
    My code matches.
    `add_job` signature: `add_job(job_id: str, data: dict) -> str`.
    My code matches.

    One thing: The prompt example says "After processing...". It doesn't show a call to `process`. It might be implied that the queue handles it or I should add `process` method. I will add `process_jobs` to make the example valid (otherwise `get_result` returns `None` immediately).
    Actually, to be safest regarding "basic", I'll stick to the requested methods and maybe add `process` as a helper since a queue needs a consumer.
    Okay, ready to generate.

    Wait, I should check if I need to handle the case where `job_id` is already in the queue? The prompt says "Each job has a unique job_id". I'll assume the caller ensures uniqueness or I just add it. I'll just append.

    Final check on "Write only the Python code". I will output the code block.

    One more thing: The prompt example usage:
    ```python
    queue = JobQueue()
    job_id = queue.add_job("job1", {"task": "process_data"})
    # After processing...
    result = queue.get_result("job1")
    ```
    If I don't add a `process` method, the example is incomplete logically. I will add `process_jobs` method to the class.

    Wait, does "Write only the Python code" mean I shouldn't include the example usage in the output? Yes, just the implementation.

    Code plan:
    1. Import deque.
    2. Class JobQueue.
    3. Init.
    4. add_job.
    5. process_jobs (to make it functional).
    6. get_result.

    Wait, strictly speaking, I should only implement the methods requested if I want to be pedantic, but a queue without a consumer is useless. I will add `process_jobs` to ensure the functionality matches the "processing" requirement.

    Wait, I can also simulate processing inside `get_result` if I mark it as "done". But `process_jobs` is clearer.

    Let's finalize the code.

```python
from collections import deque
from typing import Dict, Optional

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._job_data = {}
        self._results = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._job_data[job_id] = data
        return job_id

    def process_jobs(self):
        while self._queue:
            job_id = self._queue.popleft()
            data = self._job_data.get(job_id)
            self._results[job_id] = {"status": "completed", "input": data}

    def get_result(self, job_id: str) -> Optional[dict]:
        return self._results.get(job_id)
```
    Wait, `Optional[dict]` is better than `dict | None` for compatibility if using older Python, but `dict | None` is valid in 3.10+. The prompt uses `dict | None`. I will use `dict | None` to match prompt style, or `Optional[dict]` from typing. I'll use `dict | None` to match the prompt's type hint style exactly.

    Re-reading prompt: `get_result(job_id: str) -> dict | None`.
    I will use `dict | None`.

    Also, I should ensure imports are present.

    One detail: "The queue should store jobs internally until they are processed".
    This implies the `process` step is distinct from `add`.
    Okay.

    Final check on constraints: "Write only the Python code".
    I will output the code block.

```python
from collections import deque
from typing import Dict, Optional

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._job_data = {}
        self._results = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._job_data[job_id] = data
        return job_id

    def process_jobs(self):
        while self._queue:
            job_id = self._queue.popleft()
            data = self._job_data.get(job_id)
            self._results[job_id] = {"status": "completed", "data": data}

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)
```
    Looks good. I'll remove `typing` import if I use `dict | None` directly (Python 3.10+). Standard practice for these prompts is usually compatible Python. I'll use `dict | None` and `from collections import deque`.

    Wait, `Optional` vs `dict | None`. The prompt uses `dict | None`. I will use that.
    I will remove `typing` import to keep it minimal and Pythonic (3.10+ style).

    One more check: The prompt asks for `add_job` returning `job_id`.
    It also says "Each job has a unique job_id that is returned when added".
    My implementation returns the passed `job_id`. This is consistent.

    Okay, ready.

    Wait, I should make sure `process_jobs` is clear.
    I'll just call it `process` to be concise.
    Actually, `process_jobs` is more descriptive. I'll stick with `process_jobs`.

    Wait, I need to make sure I don't write explanations. Just code.

    One edge case: `job_id` collision. The requirement says "unique job_id". I don't need to enforce it, just assume the input is valid or overwrite. I'll just append.

    Final Code Structure:
    1. Import deque.
    2. Class JobQueue.
    3. Methods.

    Let's write it.

</reasoning_content>

<content>
from collections import deque

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._job_data = {}
        self._results = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._job_data[job_id] = data
        return job_id

    def process_jobs(self):
        while self._queue:
            job_id = self._queue.popleft()
            data = self._job_data.get(job_id)
            self._results[job_id] = {"status": "completed", "input": data}

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)
</content>