<reasoning_content>
*   Target: A basic job queue in Python.
    *   Class name: `JobQueue`.
    *   Methods:
        *   `add_job(job_id: str, data: dict) -> str`
        *   `get_result(job_id: str) -> dict | None`
    *   Mechanism: FIFO order.
    *   Storage: Internal storage for jobs and results.
    *   Return value for `add_job`: The `job_id`.
    *   Requirement: Only Python code, no explanations.

    *   `collections.deque` is ideal for FIFO.
    *   We need to store the jobs themselves (to be processed) and the results (to be retrieved).
    *   Wait, the prompt doesn't specify *how* jobs are processed (i.e., is there a `process_next()` method?).
    *   Let's re-read the prompt: "Each job has a unique job_id... Jobs should be processed in FIFO order".
    *   The prompt implies the *existence* of a processing mechanism, even if it doesn't explicitly ask for a `process()` method in the requirement list. However, to make the example "After processing..." meaningful, there must be a way to transition a job from "pending" to "completed".
    *   Actually, looking at the `get_result` method, it returns the result. This implies there's a state where a job is finished.
    *   Let's add a `process_next` method or similar to make it a complete, testable implementation, or just implement exactly what's asked and assume the user provides the processing logic.
    *   Wait, the requirement says: "Create a `JobQueue` class with the following methods: [list]". It doesn't list a `process` method.
    *   However, if I only implement `add_job` and `get_result`, `get_result` will always return `None` unless there's a way to change the state.
    *   Let's look at typical interview/coding test patterns. Usually, if they ask for a queue, they want to see how you manage the data.
    *   Let's include a way to simulate processing or provide a `process_next` method to make the example functional.

    *Refined Plan:*
    1.  `self.queue` = `collections.deque` for FIFO jobs.
    2.  `self.results` = `{}` dictionary mapping `job_id` to the result.
    3.  `self.pending_jobs` = `{}` dictionary mapping `job_id` to its data.
    4.  Wait, if I use a deque for FIFO, the deque should store the `job_id`.

    *Class Structure:*
    ```python
    from collections import deque

    class JobQueue:
        def __init__(self):
            self.queue = deque() # stores job_ids
            self.jobs = {} # stores job_id -> data
            self.results = {} # stores job_id -> result

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

        def get_result(self, job_id: str) -> dict | None:
            return self.results.get(job_id)

        # Since the prompt asks for FIFO processing but doesn't define the 'work',
        # I'll add a method to process the next job to make it a "real" queue.
        def process_next(self):
            if not self.queue:
                return None
            job_id = self.queue.popleft()
            data = self.jobs.pop(job_id)
            # Simulate some processing logic
            result = {"status": "completed", "original_data": data}
            self.results[job_id] = result
            return result
    ```

    *Re-evaluating requirement 1:* "Create a `JobQueue` class with the **following** methods".
    If I strictly follow "following methods", I shouldn't add `process_next`. But without it, the class is useless for the "After processing..." example.
    Let's look at the prompt again. "Jobs should be processed in FIFO order". This describes the *behavior* of the queue.
    I will implement exactly what is requested, and for the sake of a functional code snippet, I'll include the `process_next` or similar, or simply ensure the structure allows for it. Actually, the standard way to interpret these prompts is to provide exactly what is asked. I will stick to the required methods but I'll implement them in a way that makes sense.

    *Actually*, if I just provide `add_job` and `get_result`, and the user wants to see it working, I'll add a simple `process_job` or a way to mock the processing.

    Wait, I'll just implement the two required methods and add a helper/internal method or a `process_job` so the user can actually use it. Or, I'll assume the "processing" happens via an external mechanism that interacts with the internal state (though the state is encapsulated).

    Let's try to make it clean.

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

    class JobQueue:
        def __init__(self):
            self._queue = deque()
            self._jobs: Dict[str, Dict[str, Any]] = {}
            self._results: Dict[str, Dict[str, Any]] = {}

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

        def get_result(self, job_id: str) -> Optional[Dict[str, Any]]:
            return self._results.get(job_id)

        def process_next(self):
            """
            Processes the next job in the queue (FIFO).
            In a real scenario, this might be done by a worker thread.
            """
            if not self._queue:
                return None
            
            job_id = self._queue.popleft()
            data = self._jobs.pop(job_id)
            
            # Simulating processing
            result = {"status": "success", "processed_data": data}
            self._results[job_id] = result
            return result
    ```

    The user said "Write only the Python code, no explanations."

    Final check on requirements:
    - `add_job(job_id: str, data: dict) -> str`: Yes.
    - `get_result(job_id: str) -> dict | None`: Yes.
    - FIFO: Yes (using `deque.popleft`).
    - Store internally: Yes.
    - Unique job_id: Yes.

    I will include a `process_next` method even though it's not explicitly in the list, because "Jobs should be processed in FIFO order" is a requirement for the *logic* of the class, and without a method to trigger processing, the class cannot satisfy the requirement of having jobs that *get* processed.

    Actually, looking at the example:
    ```python
    # After processing...
    result = queue.get_result("job1")
    ```
    This implies `process` happens. I'll add a `process_job` method.

    One more thing: the prompt says "return job_id" for `add_job`. My implementation does that.

    Let's refine the code to be as minimal and elegant as possible.

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

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

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

        def get_result(self, job_id: str) -> Optional[dict]:
            return self._results.get(job_id)

        def process_next(self):
            if not self._queue:
                return None
            job_id = self._queue.popleft()
            data = self._jobs.pop(job_id)
            # Dummy processing logic
            result = {"status": "completed", "data": data}
            self._results[job_id] = result
            return result

    if __name__ == "__main__":
        queue = JobQueue()
        job_id = queue.add_job("job1", {"task": "process_data"})
        queue.process_next()
        result = queue.get_result("job1")
        print(result)
    ```

    Wait, the prompt asks for "Implement a basic job queue... Write only the Python code". I will provide the class. I'll include `process_next` to make it functional.

    Actually, I'll check if there's any ambiguity in "Jobs should be processed in FIFO order". Does it mean I should implement a background thread? No, "basic job queue" usually implies the data structure and the interface. A background thread makes it complex and might violate "basic". A `process_next` method is the standard way to demonstrate FIFO in a single-threaded context.

    One detail: `get_result(job_id: str) -> dict | None`. Python 3.10+ supports `|`. I'll use `Optional` or `|` depending on common practice. The prompt uses `dict | None`, so I will use that.

    Final code structure:
    - `collections.deque`
    - `JobQueue` class
    - `add_job`
    - `get_result`
    - `process_next` (to fulfill the "processed in FIFO" requirement)

    Actually, I'll just implement exactly what was requested to avoid "over-engineering" if the user is testing strict adherence to method names. But if I don't include a processing method, the example provided in the prompt won't work.

    Let's look at the prompt's example:
    ```python
    queue = JobQueue()
    job_id = queue.add_job("job1", {"task": "process_data"})
    # After processing...
    result = queue.get_result("job1")
    ```
    The `# After processing...` is a comment. This implies the processing is an external event or a method I should provide. I'll provide `process_next`.

    ```python
    from collections import deque

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

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

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

        def process_next(self) -> dict | None:
            if not self._queue:
                return None
            
            job_id = self._queue.popleft()
            data = self._jobs.pop(job_id)
            
            # Simulate processing
            result = {"status": "success", "data": data}
            self._results[job_id] = result
            return result
    ```

    Wait, one more thing. The `add_job` says `job_id: str`. If the user passes a `job_id` that already exists, the prompt doesn't specify behavior. I'll assume `job_id` is unique as per requirement 4.

    Final decision: Provide exactly what was requested, plus a `process_next` method so the logic is complete and the example makes sense.

    One small correction: the prompt says "return job_id". If I pass "job1", it returns "job1".

    ```python
    from collections import deque

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

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

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

        def process_next(self) -> dict | None:
            if not self._queue:
                return None
            
            job_id = self._queue.popleft()
            data = self._jobs.pop(job_id)
            
            # Simulate processing by returning the data as a result
            result = {"status": "completed", "data": data}
            self._results[job_id] = result
            return result

    if __name__ == "__main__":
        queue = JobQueue()
        job_id = queue.add_job("job1", {"task": "process_data"})
        queue.process_next()
        result = queue.get_result("job1")
        print(result)
    ```

    Wait, I should probably not include the `if __name__ == "__main__":` unless it's helpful. The user asked for "only the Python code". I'll just provide the class.

    Final check on `get_result` signature: `dict | None`. This requires Python 3.10+. I'll assume the environment is modern.

    Double check: "Each job has a unique job_id that is returned when added".
    `add_job("job1", ...)` returns `"job1"`. Correct.

    Final Code:
    ```python
    from collections import deque

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

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

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

        def process_next(self) -> dict | None:
            if not self._queue:
                return None
            
            job_id = self._queue.popleft()
            data = self._jobs.pop(job_id)
            
            # Simulate job processing
            result = {"status": "completed", "data": data}
            self._results[job_id] = result
            return result
    ```
    (Self-correction: The prompt says "Jobs should be processed in FIFO order". If I don't provide a way to process, I haven't really implemented a "queue" that is "processed", just a "storage" for jobs. The `process_next` is essential.)
</reasoning_content>

<content>
```python
from collections import deque

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

    def add_job(self, job_id: str, data: dict) -> str:
        """Adds a job to the queue and returns the job_id."""
        self._jobs[job_id] = data
        self._queue.append(job_id)
        return job_id

    def get_result(self, job_id: str) -> dict | None:
        """Returns the result of a completed job, or None if not completed."""
        return self._results.get(job_id)

    def process_next(self) -> dict | None:
        """
        Processes the next job in the queue using FIFO order.
        In a real-world scenario, this might be handled by a worker thread.
        """
        if not self._queue:
            return None

        job_id = self._queue.popleft()
        data = self._jobs.pop(job_id)

        # Simulate processing logic
        result = {"status": "completed", "processed_data": data}
        self._results[job_id] = result
        return result
```
</content>