"""Integration tests for job payload encryption with queue."""

from __future__ import annotations

import pytest

from oclawma.encryption import EncryptionManager
from oclawma.queue import JobQueue


class TestQueueEncryptionIntegration:
    """Test integration of encryption with job queue."""

    @pytest.fixture
    def encryption_manager(self):
        """Create an encryption manager for testing."""
        manager = EncryptionManager()
        manager.add_encrypted_type("sensitive")
        manager.add_encrypted_type("payment")
        return manager

    @pytest.fixture
    def queue(self, tmp_path, encryption_manager):
        """Create a temporary queue with encryption for testing."""
        db_path = tmp_path / "test_encrypted_queue.db"
        with JobQueue(db_path, encryption_manager=encryption_manager) as q:
            yield q

    def test_enqueue_without_encryption(self, queue):
        """Test that regular jobs are not encrypted."""
        job = queue.enqueue({"task": "test", "data": "public"})

        assert job.id is not None
        assert job.encrypted is False
        assert job.payload == {"task": "test", "data": "public"}

        # Verify stored in DB is not encrypted
        stored = queue.get_job(job.id, decrypt=False)
        assert stored.encrypted is False
        assert stored.payload == {"task": "test", "data": "public"}

    def test_enqueue_with_encryption(self, queue):
        """Test that sensitive jobs are encrypted."""
        job = queue.enqueue({"task": "test", "ssn": "123-45-6789"}, job_type="sensitive")

        assert job.id is not None
        # Before dequeue, job is returned as-is (encrypted)
        # Actually in our implementation we encrypt before storing

        # Verify stored in DB is encrypted
        stored = queue.get_job(job.id, decrypt=False)
        assert stored.encrypted is True
        assert "__encrypted__" in stored.payload
        # Original data should NOT be visible
        assert "ssn" not in stored.payload

    def test_dequeue_decrypts_payload(self, queue):
        """Test that dequeue decrypts encrypted payloads."""
        original_payload = {"task": "test", "api_key": "secret123"}

        queue.enqueue(original_payload, job_type="sensitive")

        # Dequeue should return decrypted payload
        job = queue.dequeue()

        assert job is not None
        assert job.payload == original_payload
        assert job.encrypted is True  # Still marked as encrypted
        assert "api_key" in job.payload
        assert job.payload["api_key"] == "secret123"

    def test_encryption_type_not_in_list(self, queue):
        """Test that job types not in encrypted_types are not encrypted."""
        job = queue.enqueue({"task": "test"}, job_type="normal")

        stored = queue.get_job(job.id, decrypt=False)
        assert stored.encrypted is False
        assert "__encrypted__" not in stored.payload

    def test_multiple_job_types_mixed(self, queue):
        """Test mixing encrypted and non-encrypted jobs."""
        # Add some encrypted jobs
        queue.enqueue({"secret": "data1"}, job_type="sensitive")
        queue.enqueue({"secret": "data2"}, job_type="payment")

        # Add non-encrypted job
        queue.enqueue({"public": "data"}, job_type="normal")

        # Process all jobs
        processed = []
        for _ in range(3):
            job = queue.dequeue()
            if job:
                processed.append((job.job_type, job.payload, job.encrypted))
                queue.complete(job.id)

        assert len(processed) == 3

        # Check that sensitive jobs were encrypted but decrypted on dequeue
        for job_type, payload, encrypted in processed:
            if job_type in ("sensitive", "payment"):
                assert encrypted is True
                assert "secret" in payload
            else:
                assert encrypted is False
                assert "public" in payload

    def test_get_job_with_decrypt_flag(self, queue):
        """Test get_job with and without decryption."""
        original = {"secret": "value"}
        job = queue.enqueue(original, job_type="sensitive")

        # With decryption (default)
        decrypted = queue.get_job(job.id, decrypt=True)
        assert decrypted.payload == original

        # Without decryption
        encrypted = queue.get_job(job.id, decrypt=False)
        assert encrypted.encrypted is True
        assert "__encrypted__" in encrypted.payload

    def test_list_jobs_decrypt_option(self, queue):
        """Test list_jobs with decrypt option."""
        queue.enqueue({"secret": "1"}, job_type="sensitive")
        queue.enqueue({"secret": "2"}, job_type="sensitive")

        # List without decryption
        encrypted_jobs = queue.list_jobs(decrypt=False)
        for job in encrypted_jobs:
            assert job.encrypted is True
            assert "__encrypted__" in job.payload

        # List with decryption (default)
        decrypted_jobs = queue.list_jobs(decrypt=True)
        for job in decrypted_jobs:
            assert "secret" in job.payload
            assert "__encrypted__" not in job.payload
