"""Performance benchmarks for pyarchive functionality."""

from __future__ import annotations

import shutil
import tempfile
import time
from pathlib import Path
from unittest.mock import Mock

import pytest

from ..components.archiver import (
    PyArchiveConfig,
    PyArchiver,
)


@pytest.fixture(scope="session")
def sample_files():
    """Create sample files for benchmarking."""
    # Use session scope to keep files alive for entire test session
    temp_dir = tempfile.mkdtemp()
    dist_dir = Path(temp_dir) / "dist"
    dist_dir.mkdir()

    # Create sample files of different sizes
    small_file = dist_dir / "small.txt"
    small_file.write_text("A" * 1000, encoding="utf-8")  # ~1KB

    medium_file = dist_dir / "medium.txt"
    medium_file.write_text("B" * 100000, encoding="utf-8")  # ~100KB

    large_file = dist_dir / "large.txt"
    large_file.write_text("C" * 1000000, encoding="utf-8")  # ~1MB

    # Create some binary-like data
    binary_file = dist_dir / "binary.dat"
    binary_file.write_bytes(b"X" * 500000)  # ~500KB

    # Create nested directory structure
    subdir = dist_dir / "subdir"
    subdir.mkdir()
    nested_file = subdir / "nested.txt"
    nested_file.write_text("D" * 50000, encoding="utf-8")  # ~50KB

    yield dist_dir

    shutil.rmtree(temp_dir, ignore_errors=True)


@pytest.mark.benchmark(group="archive-formats")
def test_zip_archive_performance(benchmark, sample_files):
    """Benchmark ZIP archive creation performance."""

    def create_archive():
        with tempfile.TemporaryDirectory() as output_temp:
            output_file = Path(output_temp) / "test.zip"
            ignore_patterns = set()
            config = PyArchiveConfig(compression_level=6)

            mock_project = Mock()
            mock_project.name = "test_project"
            mock_project.version = "1.0.0"

            archiver = PyArchiver(root_dir=Path(""), config=config)

            result = archiver._archive_zip(
                dist_dir=sample_files,
                output_file=output_file,
                ignore_patterns=ignore_patterns,
            )
            # Check within temp directory scope
            file_exists = output_file.exists()
            file_size = output_file.stat().st_size if file_exists else 0
            return result, file_exists, file_size

    result, file_exists, file_size = benchmark(create_archive)
    assert result is True
    assert file_exists is True
    assert file_size > 0


@pytest.mark.benchmark(group="archive-formats")
def test_tar_archive_performance(benchmark, sample_files):
    """Benchmark TAR archive creation performance."""

    def create_archive():
        with tempfile.TemporaryDirectory() as output_temp:
            output_file = Path(output_temp) / "test.tar"
            ignore_patterns = set()
            config = PyArchiveConfig()

            mock_project = Mock()
            mock_project.name = "test_project"
            mock_project.version = "1.0.0"

            archiver = PyArchiver(root_dir=Path(""), config=config)

            result = archiver._archive_tar(
                dist_dir=sample_files,
                output_file=output_file,
                ignore_patterns=ignore_patterns,
            )
            # Check within temp directory scope
            file_exists = output_file.exists()
            file_size = output_file.stat().st_size if file_exists else 0
            return result, file_exists, file_size

    result, file_exists, file_size = benchmark(create_archive)
    assert result is True
    assert file_exists is True
    assert file_size > 0


@pytest.mark.benchmark(group="archive-formats")
def test_gztar_archive_performance(benchmark, sample_files):
    """Benchmark gzip-compressed TAR archive creation performance."""

    def create_archive():
        with tempfile.TemporaryDirectory() as output_temp:
            output_file = Path(output_temp) / "test.tar.gz"
            ignore_patterns = set()
            config = PyArchiveConfig(compression_level=6)

            mock_project = Mock()
            mock_project.name = "test_project"
            mock_project.version = "1.0.0"

            archiver = PyArchiver(root_dir=Path(""), config=config)

            result = archiver._archive_gztar(
                dist_dir=sample_files,
                output_file=output_file,
                ignore_patterns=ignore_patterns,
            )
            # Check within temp directory scope
            file_exists = output_file.exists()
            file_size = output_file.stat().st_size if file_exists else 0
            return result, file_exists, file_size

    result, file_exists, file_size = benchmark(create_archive)
    assert result is True
    assert file_exists is True
    assert file_size > 0


@pytest.mark.benchmark(group="archive-formats")
def test_bztar_archive_performance(benchmark, sample_files):
    """Benchmark bzip2-compressed TAR archive creation performance."""

    def create_archive():
        with tempfile.TemporaryDirectory() as output_temp:
            output_file = Path(output_temp) / "test.tar.bz2"
            ignore_patterns = set()
            config = PyArchiveConfig()

            mock_project = Mock()
            mock_project.name = "test_project"
            mock_project.version = "1.0.0"

            archiver = PyArchiver(root_dir=Path(""), config=config)

            result = archiver._archive_bztar(
                dist_dir=sample_files,
                output_file=output_file,
                ignore_patterns=ignore_patterns,
            )
            # Check within temp directory scope
            file_exists = output_file.exists()
            file_size = output_file.stat().st_size if file_exists else 0
            return result, file_exists, file_size

    result, file_exists, file_size = benchmark(create_archive)
    assert result is True
    assert file_exists is True
    assert file_size > 0


@pytest.mark.benchmark(group="archive-formats")
def test_xztar_archive_performance(benchmark, sample_files):
    """Benchmark xz-compressed TAR archive creation performance."""

    def create_archive():
        with tempfile.TemporaryDirectory() as output_temp:
            output_file = Path(output_temp) / "test.tar.xz"
            ignore_patterns = set()
            config = PyArchiveConfig()

            mock_project = Mock()
            mock_project.name = "test_project"
            mock_project.version = "1.0.0"

            archiver = PyArchiver(root_dir=Path(""), config=config)

            result = archiver._archive_xztar(
                dist_dir=sample_files,
                output_file=output_file,
                ignore_patterns=ignore_patterns,
            )
            # Check within temp directory scope
            file_exists = output_file.exists()
            file_size = output_file.stat().st_size if file_exists else 0
            return result, file_exists, file_size

    result, file_exists, file_size = benchmark(create_archive)
    assert result is True
    assert file_exists is True
    assert file_size > 0


@pytest.mark.benchmark(group="compression-levels")
def test_different_compression_levels_zip(benchmark):
    """Benchmark ZIP with different compression levels."""
    with tempfile.TemporaryDirectory() as temp_dir:
        dist_dir = Path(temp_dir) / "dist"
        dist_dir.mkdir()

        # Create medium-sized test file
        test_file = dist_dir / "test.txt"
        test_file.write_text("A" * 200000, encoding="utf-8")  # ~200KB

        def create_archive_with_level():
            # Test one compression level per benchmark call
            level = 6  # Default level
            with tempfile.TemporaryDirectory() as output_temp:
                output_file = Path(output_temp) / f"test_level_{level}.zip"
                ignore_patterns = set()
                config = PyArchiveConfig(compression_level=level)

                mock_project = Mock()
                mock_project.name = "test_project"
                mock_project.version = "1.0.0"

                archiver = PyArchiver(root_dir=Path(""), config=config)

                result = archiver._archive_zip(
                    dist_dir=dist_dir,
                    output_file=output_file,
                    ignore_patterns=ignore_patterns,
                )
                file_size = output_file.stat().st_size if result and output_file.exists() else 0
                return result, file_size

        result, size = benchmark(create_archive_with_level)
        assert result is True
        assert size > 0


@pytest.mark.benchmark(group="compression-levels")
def test_different_compression_levels_gztar(benchmark):
    """Benchmark gzip TAR with different compression levels."""
    with tempfile.TemporaryDirectory() as temp_dir:
        dist_dir = Path(temp_dir) / "dist"
        dist_dir.mkdir()

        # Create medium-sized test file
        test_file = dist_dir / "test.txt"
        test_file.write_text("B" * 200000, encoding="utf-8")  # ~200KB

        def create_archive_with_level():
            # Test one compression level per benchmark call
            level = 6  # Default level
            with tempfile.TemporaryDirectory() as output_temp:
                output_file = Path(output_temp) / f"test_level_{level}.tar.gz"
                ignore_patterns = set()
                config = PyArchiveConfig(compression_level=level)

                mock_project = Mock()
                mock_project.name = "test_project"
                mock_project.version = "1.0.0"

                archiver = PyArchiver(root_dir=Path(""), config=config)

                result = archiver._archive_gztar(
                    dist_dir=dist_dir,
                    output_file=output_file,
                    ignore_patterns=ignore_patterns,
                )
                file_size = output_file.stat().st_size if result and output_file.exists() else 0
                return result, file_size

        result, size = benchmark(create_archive_with_level)
        assert result is True
        assert size > 0


@pytest.mark.benchmark(group="ignore-patterns")
def test_ignore_patterns_performance(benchmark):
    """Benchmark archive creation with ignore patterns."""
    with tempfile.TemporaryDirectory() as temp_dir:
        dist_dir = Path(temp_dir) / "dist"
        dist_dir.mkdir()

        # Create files that should be ignored
        ignore_files = [".git", "__pycache__", "test.pyc", "temp.log"]
        for filename in ignore_files:
            (dist_dir / filename).write_text("ignored content", encoding="utf-8")

        # Create files that should be included
        include_files = ["main.py", "config.json", "data.txt"]
        for filename in include_files:
            (dist_dir / filename).write_text("included content", encoding="utf-8")

        def create_archive():
            with tempfile.TemporaryDirectory() as output_temp:
                output_file = Path(output_temp) / "test.zip"
                ignore_patterns = {".git", "__pycache__", "*.pyc", "*.log"}
                config = PyArchiveConfig()

                mock_project = Mock()
                mock_project.name = "test_project"
                mock_project.version = "1.0.0"

                archiver = PyArchiver(root_dir=Path(""), config=config)

                return archiver._archive_zip(
                    dist_dir=dist_dir,
                    output_file=output_file,
                    ignore_patterns=ignore_patterns,
                )

        result = benchmark(create_archive)
        assert result is True


@pytest.mark.benchmark(group="large-files")
def test_large_file_handling(benchmark):
    """Benchmark handling of large files."""
    with tempfile.TemporaryDirectory() as temp_dir:
        dist_dir = Path(temp_dir) / "dist"
        dist_dir.mkdir()

        # Create a larger test file
        large_file = dist_dir / "large_data.bin"
        large_file.write_bytes(b"X" * 5000000)  # ~5MB

        def create_archive():
            with tempfile.TemporaryDirectory() as output_temp:
                output_file = Path(output_temp) / "large_test.zip"
                ignore_patterns = set()
                config = PyArchiveConfig(compression_level=1)  # Lower compression for speed

                mock_project = Mock()
                mock_project.name = "test_project"
                mock_project.version = "1.0.0"

                archiver = PyArchiver(root_dir=Path(""), config=config)

                result = archiver._archive_zip(
                    dist_dir=dist_dir,
                    output_file=output_file,
                    ignore_patterns=ignore_patterns,
                )
                file_size = output_file.stat().st_size if result and output_file.exists() else 0
                return result, file_size

        result, size = benchmark(create_archive)
        assert result is True
        # With compression level 1, we expect some compression but not extreme
        # The original 5MB of repeated 'X' bytes should compress significantly
        # Let's expect at least a small file created (even highly compressed)
        assert size > 0  # Should be greater than 0


def test_format_comparison_summary(sample_files):
    """Compare performance across different formats (not a benchmark)."""
    # Create archiver instance for testing
    config = PyArchiveConfig()
    archiver = PyArchiver(root_dir=Path(""), config=config)

    formats_to_test = [
        ("zip", archiver._archive_zip),
        ("tar", archiver._archive_tar),
        ("gztar", archiver._archive_gztar),
        ("bztar", archiver._archive_bztar),
        ("xztar", archiver._archive_xztar),
    ]

    results = {}

    for format_name, archive_func in formats_to_test:
        with tempfile.TemporaryDirectory() as output_temp:
            output_file = Path(output_temp) / f"test.{format_name}"
            ignore_patterns = set()

            start_time = time.perf_counter()
            result = archive_func(sample_files, output_file, ignore_patterns)
            end_time = time.perf_counter()

            if result and output_file.exists():
                results[format_name] = {
                    "success": True,
                    "time": end_time - start_time,
                    "size": output_file.stat().st_size,
                }
            else:
                results[format_name] = {"success": False, "time": 0, "size": 0}

    # Print comparison results
    print("\nFormat Performance Comparison:")
    print("-" * 50)
    for format_name, data in results.items():
        if data["success"]:
            print(f"{format_name:>8}: {data['time']:.3f}s, {data['size']:,} bytes")
        else:
            print(f"{format_name:>8}: FAILED")
