```python
from collections import deque

class JobQueue:
    """
    Implements a priority-based job scheduling queue.
    Higher priority numbers (2 > 1 > 0) are processed first.
    FIFO order is maintained for jobs with the same priority.
    """
    def __init__(self):
        # Structure: (negative_priority, insertion_index, job_name, job_data)
        # Negative priority ensures that when sorting ascendingly,
        # higher priority jobs (e.g., -2) come before lower ones (e.g., -0).
        self.jobs = []
        self.insertion_counter = 0

    def add_job(self, job_name: str, job_data: dict, priority: int = 0):
        """
        Adds a new job to the queue with a specified priority.
        """
        # Store negative priority for sorting convenience
        neg_priority = -priority
        
        self.jobs.append((neg_priority, self.insertion_counter, job_name, job_data))
        self.insertion_counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        """
        Retrieves and removes the highest priority job.
        If priorities are equal, the job added earliest is chosen (FIFO).
        Returns (job_name, job_data) or None if the queue is empty.
        """
        if not self.jobs:
            return None

        # The job with the highest priority (most negative neg_priority)
        # and earliest insertion index will be the first element after sorting.
        # We sort primarily by neg_priority (ascending) and secondarily by index (ascending).
        self.jobs.sort()

        # Pop the first job (highest priority, oldest insertion)
        neg_priority, _, job_name, job_data = self.jobs.pop(0)
        
        return job_name, job_data

if __name__ == '__main__':
    # Example 1: Basic Priority Test
    queue1 = JobQueue()
    queue1.add_job("normal_1", {"type": "normal"}, priority=0)
    queue1.add_job("critical_1", {"type": "critical"}, priority=2)
    queue1.add_job("high_1", {"type": "high"}, priority=1)

    print("--- Queue 1 (Priority Test) ---")
    # Expected order: Critical (2), High (1), Normal (0)
    job1 = queue1.get_next_job()
    print(f"Job 1: {job1[0]}")  # critical_1
    job2 = queue1.get_next_job()
    print(f"Job 2: {job2[0]}")  # high_1
    job3 = queue1.get_next_job()
    print(f"Job 3: {job3[0]}")  # normal_1

    # Example 2: FIFO Stability Test
    queue2 = JobQueue()
    queue2.add_job("normal_A", {"type": "normal"}, priority=0)
    queue2.add_job("high_A", {"type": "high"}, priority=1)
    queue2.add_job("normal_B", {"type": "normal"}, priority=0)
    queue2.add_job("high_B", {"type": "high"}, priority=1)

    print("\n--- Queue 2 (FIFO Stability Test) ---")
    # Expected order: High_A (FIFO tiebreak), High_B, Normal_A (FIFO tiebreak), Normal_B
    
    # High_A (Priority 1, added first)
    job_a = queue2.get_next_job()
    print(f"Job A: {job_a[0]}") 
    
    # High_B (Priority 1, added second)
    job_b = queue2.get_next_job()
    print(f"Job B: {job_b[0]}") 
    
    # Normal_A (Priority 0, added first)
    job_c = queue2.get_next_job()
    print(f"Job C: {job_c[0]}") 
    
    # Normal_B (Priority 0, added second)
    job_d = queue2.get_next_job()
    print(f"Job D: {job_d[0]}") 
    
    # Example 3: Empty Queue
    queue3 = JobQueue()
    print("\n--- Queue 3 (Empty Test) ---")
    print(f"Next job: {queue3.get_next_job()}") # None
```