"""Performance benchmarks for pdfcrypt module."""

from __future__ import annotations

import atexit
import tempfile
from pathlib import Path

import pytest
from pypdf import PdfWriter

from pytola.office.pdfcrypt.pdfcrypt import decrypt_pdf, encrypt_pdf


@pytest.fixture(autouse=True)
def disable_config_save():
    """Disable configuration auto-save during tests to prevent logging errors."""
    # Remove the atexit handler that saves config
    import pytola.office.pdfcrypt.pdfcrypt as pdfcrypt_module

    atexit.unregister(pdfcrypt_module.conf.save)
    yield
    # Re-register the handler after test
    atexit.register(pdfcrypt_module.conf.save)


@pytest.fixture
def large_pdf_file():
    """Create a larger PDF file for performance testing."""
    with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
        writer = PdfWriter()
        # Create a PDF with multiple pages
        for _i in range(10):
            writer.add_blank_page(width=200, height=200)
        with open(tmp_file.name, "wb") as f:
            writer.write(f)
        file_path = Path(tmp_file.name)
        yield file_path
        # Cleanup - handle Windows file locking
        try:
            file_path.unlink(missing_ok=True)
        except PermissionError:
            # On Windows, file might still be locked, try again later
            import time

            time.sleep(0.1)
            try:
                file_path.unlink(missing_ok=True)
            except PermissionError:
                pass  # Give up if still locked


@pytest.fixture
def medium_pdf_file():
    """Create a medium-sized PDF file for performance testing."""
    with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
        writer = PdfWriter()
        # Create a PDF with fewer pages
        for _i in range(3):
            writer.add_blank_page(width=200, height=200)
        with open(tmp_file.name, "wb") as f:
            writer.write(f)
        file_path = Path(tmp_file.name)
        yield file_path
        # Cleanup - handle Windows file locking
        try:
            file_path.unlink(missing_ok=True)
        except PermissionError:
            # On Windows, file might still be locked, try again later
            import time

            time.sleep(0.1)
            try:
                file_path.unlink(missing_ok=True)
            except PermissionError:
                pass  # Give up if still locked


class TestPerformanceBenchmarks:
    """Performance benchmark tests."""

    @pytest.mark.benchmark(group="encryption")
    def test_encrypt_single_large_file(self, benchmark, large_pdf_file):
        """Benchmark encryption of a single large PDF file."""
        password = "benchmarkpassword123"

        def encrypt_operation():
            return encrypt_pdf(large_pdf_file, password)

        result = benchmark(encrypt_operation)
        assert result[1] is not None  # Encrypted file should exist

    @pytest.mark.benchmark(group="encryption")
    def test_encrypt_single_medium_file(self, benchmark, medium_pdf_file):
        """Benchmark encryption of a single medium PDF file."""
        password = "benchmarkpassword123"

        def encrypt_operation():
            return encrypt_pdf(medium_pdf_file, password)

        result = benchmark(encrypt_operation)
        assert result[1] is not None

    @pytest.mark.benchmark(group="decryption")
    def test_decrypt_single_file(self, benchmark, medium_pdf_file):
        """Benchmark decryption of a single PDF file."""
        password = "benchmarkpassword123"
        # First encrypt the file
        _, encrypted_file = encrypt_pdf(medium_pdf_file, password)
        assert encrypted_file is not None

        def decrypt_operation():
            return decrypt_pdf(encrypted_file, password)

        result = benchmark(decrypt_operation)
        assert result[1] is not None  # Decrypted file should exist

    @pytest.mark.benchmark(group="operations")
    def test_complete_encrypt_decrypt_cycle(self, benchmark, medium_pdf_file):
        """Benchmark complete encrypt-decrypt cycle."""
        password = "benchmarkpassword123"

        def complete_cycle():
            # Encrypt
            _, encrypted = encrypt_pdf(medium_pdf_file, password)
            if encrypted is None:
                return None
            # Decrypt
            _, decrypted = decrypt_pdf(encrypted, password)
            return decrypted

        result = benchmark(complete_cycle)
        assert result is not None

    @pytest.mark.benchmark(group="memory")
    def test_memory_usage_during_encryption(self, benchmark, large_pdf_file):
        """Benchmark memory usage during encryption."""
        password = "memorytest123"

        def encrypt_with_memory_tracking():
            return encrypt_pdf(large_pdf_file, password)

        result = benchmark(encrypt_with_memory_tracking)
        assert result[1] is not None


class TestScalability:
    """Scalability tests for handling multiple files."""

    @pytest.mark.parametrize("file_count", [1, 5, 10])
    @pytest.mark.benchmark(group="batch_processing")
    def test_multiple_file_encryption(self, benchmark, tmp_path, file_count):
        """Benchmark encryption of multiple files."""
        password = "batchtest123"
        files = []

        # Create multiple PDF files
        for i in range(file_count):
            pdf_path = tmp_path / f"test_{i}.pdf"
            writer = PdfWriter()
            writer.add_blank_page(width=100, height=100)
            with open(pdf_path, "wb") as f:
                writer.write(f)
            files.append(pdf_path)

        def batch_encrypt():
            results = []
            for pdf_file in files:
                result = encrypt_pdf(pdf_file, password)
                results.append(result)
            return results

        results = benchmark(batch_encrypt)
        # Verify all operations succeeded
        assert all(result[1] is not None for result in results)

    @pytest.mark.benchmark(group="configuration")
    def test_config_property_caching(self, benchmark):
        """Benchmark configuration property caching performance."""
        from pytola.office.pdfcrypt.pdfcrypt import PDFCryptConfig

        config = PDFCryptConfig()

        def access_cached_properties():
            # Access properties multiple times to test caching
            results = []
            for _ in range(100):
                results.append(config.is_configured)
                results.append(config.config_summary)
            return results

        results = benchmark(access_cached_properties)
        assert len(results) == 200


if __name__ == "__main__":
    pytest.main([__file__, "-v", "--benchmark-only"])
