"""Integration tests for encryption features.

Tests end-to-end encryption/decryption workflows including:
- Key management
- Payload encryption
- Encrypted queue operations
- Encryption metadata handling
"""

from __future__ import annotations

import pytest

from oclawma.encryption import (
    DecryptionError,
    EncryptionManager,
)
from oclawma.queue.queue import JobQueue


@pytest.mark.integration
@pytest.mark.encryption
class TestEncryptionWorkflow:
    """End-to-end tests for encryption workflows."""

    def test_encryption_roundtrip(self, encryption_manager: EncryptionManager):
        """Test that data can be encrypted and decrypted."""
        original_data = {"secret": "my_password", "api_key": "sk-12345"}

        # Encrypt
        encrypted = encryption_manager.encrypt_dict(original_data)

        # Verify encrypted data is different and is a string
        assert encrypted != original_data
        assert isinstance(encrypted, str)

        # Decrypt
        decrypted = encryption_manager.decrypt_dict(encrypted)

        # Verify decryption restores original
        assert decrypted == original_data

    def test_different_data_different_ciphertext(self, encryption_manager: EncryptionManager):
        """Test that same data produces different ciphertext each time."""
        data = {"test": "value"}

        encrypted1 = encryption_manager.encrypt_dict(data)
        encrypted2 = encryption_manager.encrypt_dict(data)

        # Should be different due to random IV
        assert encrypted1 != encrypted2

    def test_tampered_data_detection(self, encryption_manager: EncryptionManager):
        """Test that tampered data is detected during decryption."""
        data = {"test": "value"}

        encrypted = encryption_manager.encrypt_dict(data)

        # Tamper with encrypted data
        tampered = encrypted[:20] + "X" + encrypted[21:]

        # Decryption should fail
        with pytest.raises(DecryptionError):
            encryption_manager.decrypt_dict(tampered)

    def test_wrong_key_fails(self):
        """Test that decryption with wrong key fails."""
        key1 = b"correct-key-32-bytes-long-here!!"
        key2 = b"wrong-key--32-bytes-long-here!!!"

        manager1 = EncryptionManager(key1)
        manager2 = EncryptionManager(key2)

        data = {"secret": "value"}
        encrypted = manager1.encrypt_dict(data)

        # Decrypt with wrong key should fail
        with pytest.raises(DecryptionError):
            manager2.decrypt_dict(encrypted)


@pytest.mark.integration
@pytest.mark.encryption
class TestEncryptedQueue:
    """End-to-end tests for encrypted queue operations."""

    def test_encrypted_job_enqueue_dequeue(self, queue_with_encryption: JobQueue):
        """Test enqueueing and dequeueing encrypted jobs."""
        queue = queue_with_encryption

        sensitive_data = {"ssn": "123-45-6789", "dob": "1990-01-01"}

        # Enqueue encrypted job
        queue.enqueue(
            sensitive_data,
            job_type="pii_processing",
        )

        # Dequeue and verify data is available
        dequeued_job, _ = queue.dequeue_with_rate_limit()
        assert dequeued_job is not None
        assert dequeued_job.payload == sensitive_data

        # Complete the job
        queue.complete(dequeued_job.id)

    def test_mixed_jobs_in_queue(self, queue_with_encryption: JobQueue):
        """Test queue with multiple jobs."""
        queue = queue_with_encryption

        # Add jobs
        queue.enqueue({"task": "job1"})
        queue.enqueue({"task": "job2"})

        # Process both
        processed = []
        for _ in range(2):
            job, _ = queue.dequeue_with_rate_limit()
            if job:
                processed.append(job)
                queue.complete(job.id)

        assert len(processed) == 2
