"""Benchmark tests for zipencrypt module performance."""

from __future__ import annotations

import tempfile
from pathlib import Path
from unittest.mock import patch

import pytest

from pytola.office.zipencrypt import (
    EncryptZipConfig,
    _create_unencrypted_zip,
    _execute_command,
    _get_valid_entries,
    _make_archive,
)


@pytest.mark.benchmark(group="command_execution")
def test_execute_command_benchmark(benchmark):
    """Benchmark _execute_command execution performance."""
    # Mock subprocess to avoid actual command execution
    with patch("subprocess.run") as mock_run:
        mock_run.return_value.stdout = "success"
        mock_run.return_value.stderr = ""

        def execute_command():
            _execute_command(["echo", "test"])
            return True

        result = benchmark(execute_command)
        assert result is True
        assert mock_run.called


@pytest.mark.benchmark(group="sequential_processing")
def test_sequential_processing_benchmark(benchmark):
    """Benchmark sequential processing performance with multiple tasks."""
    # Create test data
    test_args = [Path(f"file_{i}.txt") for i in range(10)]

    # Mock the processing function
    processed_count = 0

    def mock_process(arg):
        nonlocal processed_count
        processed_count += 1
        return f"processed {arg}"

    def run_sequential():
        nonlocal processed_count
        processed_count = 0
        for arg in test_args:
            mock_process(arg)
        return processed_count

    result = benchmark(run_sequential)
    assert result == 10  # All items should be processed


@pytest.mark.benchmark(group="configuration")
def test_config_initialization_benchmark(benchmark):
    """Benchmark configuration initialization performance."""

    def init_config():
        return EncryptZipConfig()

    config = benchmark(init_config)
    assert isinstance(config, EncryptZipConfig)


@pytest.mark.benchmark(group="configuration")
def test_config_property_caching_benchmark(benchmark):
    """Benchmark cached property performance."""

    def run_test():
        config = EncryptZipConfig()

        # Mock shutil.which to simulate real-world scenario
        with patch("shutil.which") as mock_which:
            mock_which.return_value = None  # No tools available

            # First access (should call shutil.which)
            tools1 = config.available_tools
            assert tools1 == []
            assert mock_which.call_count == 3  # Called for 7z, zip, rar

            # Reset mock for second access
            mock_which.reset_mock()

            # Second access (should use cached value)
            tools2 = config.available_tools
            assert tools2 == []
            assert mock_which.call_count == 0  # Should not be called again

    benchmark(run_test)


@pytest.mark.benchmark(group="file_operations")
def test_get_valid_entries_performance(benchmark):
    """Benchmark _get_valid_entries function with various directory sizes."""
    # Create temporary directory with test files
    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create test files and directories
        for i in range(50):
            (test_path / f"file_{i}.txt").write_text(f"Content {i}")

        # Add some hidden directories to test filtering
        (test_path / ".git").mkdir()
        (test_path / "__pycache__").mkdir()
        (test_path / "normal_dir").mkdir()

        def get_entries():
            return _get_valid_entries(test_path)

        entries = benchmark(get_entries)

        # Should have 50 files + 1 normal directory = 51 entries
        assert len(entries) == 51


@pytest.mark.benchmark(group="file_operations")
def test_create_unencrypted_zip_small_file(benchmark):
    """Benchmark ZIP creation for small file."""
    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create small test file
        test_file = test_path / "small.txt"
        test_file.write_text("Small file content")

        zip_path = test_path / "small.zip"

        def create_zip():
            _create_unencrypted_zip(test_file, zip_path)
            return zip_path.exists()

        result = benchmark(create_zip)
        assert result is True
        assert zip_path.exists()


@pytest.mark.benchmark(group="file_operations")
def test_create_unencrypted_zip_large_file(benchmark):
    """Benchmark ZIP creation for larger file."""
    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create larger test file (1MB)
        test_file = test_path / "large.txt"
        with open(test_file, "w") as f:
            f.write("A" * 1024 * 1024)  # 1MB of data

        zip_path = test_path / "large.zip"

        def create_zip():
            _create_unencrypted_zip(test_file, zip_path)
            return zip_path.exists()

        result = benchmark(create_zip)
        assert result is True
        assert zip_path.exists()


@pytest.mark.benchmark(group="file_operations")
def test_create_unencrypted_zip_directory(benchmark):
    """Benchmark ZIP creation for directory with multiple files."""
    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create directory structure
        src_dir = test_path / "src"
        src_dir.mkdir()

        # Create multiple files
        for i in range(100):
            (src_dir / f"file_{i:03d}.py").write_text(f"# Content of file {i}\nprint('Hello')")

        # Create subdirectories
        for i in range(10):
            subdir = src_dir / f"module_{i}"
            subdir.mkdir()
            (subdir / "init.py").write_text("# Init file")

        zip_path = test_path / "src.zip"

        def create_zip():
            _create_unencrypted_zip(src_dir, zip_path)
            return zip_path.exists()

        result = benchmark(create_zip)
        assert result is True
        assert zip_path.exists()


@pytest.mark.benchmark(group="workflow")
def test_make_archive_performance(benchmark):
    """Benchmark the complete archive creation workflow."""
    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create test file
        test_file = test_path / "document.pdf"
        test_file.write_text("%PDF-1.4 fake PDF content")

        # Mock the encryption support and functions to avoid external tool calls
        with patch("pytola.office.zipencrypt.conf") as mock_conf, patch(
            "pytola.office.zipencrypt._execute_command"
        ) as mock_execute:
            # Configure the mock to return empty tools list to trigger fallback path
            mock_conf.available_tools = []
            mock_execute.return_value = None

            def make_archive():
                _make_archive(test_file, "test_password", replace=True)
                return True

            result = benchmark(make_archive)
            assert result is True


@pytest.mark.benchmark(group="workflow")
def test_parallel_processing_simulation(benchmark):
    """Benchmark simulated parallel processing performance."""
    import concurrent.futures
    from functools import partial

    # Create test data
    test_files = []
    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create multiple test files
        for i in range(20):
            test_file = test_path / f"file_{i}.txt"
            test_file.write_text(f"Content of file {i}")
            test_files.append(test_file)

        # Mock functions
        with patch("pytola.office.zipencrypt._create_encrypted_zip") as mock_encrypt:
            mock_encrypt.return_value = None

            def process_file(filepath, password):
                _make_archive(filepath, password, replace=True)

            def parallel_process():
                password = "benchmark_password"
                max_workers = 4

                with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
                    futures = [executor.submit(partial(process_file, f, password)) for f in test_files]
                    concurrent.futures.wait(futures)

                return len([f for f in futures if f.done()])

            result = benchmark(parallel_process)
            assert result == 20


@pytest.mark.benchmark(group="memory")
def test_memory_usage_during_zip_creation(benchmark):
    """Benchmark memory usage during ZIP creation."""
    import os

    import psutil

    process = psutil.Process(os.getpid())

    with tempfile.TemporaryDirectory() as temp_dir:
        test_path = Path(temp_dir)

        # Create moderately sized test file
        test_file = test_path / "medium.txt"
        with open(test_file, "w") as f:
            for i in range(10000):
                f.write(f"Line {i}: This is test content for memory benchmarking\n")

        zip_path = test_path / "medium.zip"

        def create_zip_with_memory_tracking():
            initial_memory = process.memory_info().rss
            _create_unencrypted_zip(test_file, zip_path)
            final_memory = process.memory_info().rss
            return final_memory - initial_memory

        memory_delta = benchmark(create_zip_with_memory_tracking)

        # Memory usage should be reasonable (less than 100MB increase)
        assert memory_delta < 100 * 1024 * 1024  # 100MB


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