"""Performance benchmarks for img2ico functionality."""

from pathlib import Path
from typing import Callable

import pytest
from PIL import Image

from pytola_office.img2ico.cli import (
    ImageToIcoConfig,
    ImageToIcoRunner,
    is_valid_image,
    parse_sizes,
)


class TestParseSizesBenchmark:
    """Benchmarks for parse_sizes function."""

    @pytest.mark.benchmark
    def test_parse_sizes_performance(self, benchmark: Callable) -> None:
        """Benchmark parse_sizes function performance."""
        result = benchmark(parse_sizes, "16,32,48,64,128,256")
        assert len(result) == 6

    @pytest.mark.benchmark
    def test_parse_sizes_with_spaces_performance(self, benchmark: Callable) -> None:
        """Benchmark parse_sizes with spaces performance."""
        result = benchmark(parse_sizes, "16, 32, 48, 64, 128, 256")
        assert len(result) == 6


class TestIsValidImageBenchmark:
    """Benchmarks for is_valid_image function."""

    @pytest.fixture
    def valid_image(self, tmp_path) -> Path:
        """Create a valid test image."""
        img_path = tmp_path / "test.png"
        img = Image.new("RGB", (1000, 1000), color="red")
        img.save(img_path, "PNG")
        return img_path

    @pytest.mark.benchmark
    def test_is_valid_image_performance(self, benchmark, valid_image) -> None:
        """Benchmark is_valid_image function performance."""
        result = benchmark(is_valid_image, valid_image)
        assert result is True


class TestImageToIcoRunnerBenchmark:
    """Benchmarks for ImageToIcoRunner class."""

    @pytest.fixture
    def sample_image_small(self, tmp_path) -> Path:
        """Create a small test image."""
        img_path = tmp_path / "small.png"
        img = Image.new("RGBA", (100, 100), color=(255, 0, 0, 255))
        img.save(img_path, "PNG")
        return img_path

    @pytest.fixture
    def sample_image_large(self, tmp_path) -> Path:
        """Create a large test image."""
        img_path = tmp_path / "large.png"
        img = Image.new("RGBA", (1000, 1000), color=(0, 255, 0, 255))
        img.save(img_path, "PNG")
        return img_path

    @pytest.mark.benchmark
    def test_runner_initialization_performance(self, benchmark, sample_image_small) -> None:
        """Benchmark ImageToIcoRunner initialization performance."""
        runner = benchmark(lambda: ImageToIcoRunner(input_path=sample_image_small))
        assert runner.input_path == sample_image_small

    @pytest.mark.benchmark
    def test_single_file_conversion_small(self, benchmark, sample_image_small, tmp_path) -> None:
        """Benchmark single file conversion with small image."""
        output_path = tmp_path / "output.ico"
        runner = ImageToIcoRunner(input_path=sample_image_small, output_path=output_path)

        result = benchmark(runner.run)

        # Verify conversion completed
        assert output_path.exists()
        assert result is None  # run() returns None

    @pytest.mark.benchmark
    def test_single_file_conversion_large(self, benchmark, sample_image_large, tmp_path) -> None:
        """Benchmark single file conversion with large image."""
        output_path = tmp_path / "output.ico"
        runner = ImageToIcoRunner(
            input_path=sample_image_large,
            output_path=output_path,
            sizes={16, 32, 64},  # Use fewer sizes for faster testing
        )

        result = benchmark(runner.run)

        assert output_path.exists()
        assert result is None

    @pytest.mark.benchmark
    def test_resize_for_icon_performance(self, benchmark, sample_image_small) -> None:
        """Benchmark _resize_for_icon method performance."""
        runner = ImageToIcoRunner(input_path=sample_image_small)

        with Image.open(str(sample_image_small)) as img:
            resized = benchmark(runner._resize_for_icon, img, 64)

        assert resized.width == 64
        assert resized.height == 64

    @pytest.mark.benchmark
    def test_resize_quality_modes_performance(self, benchmark, sample_image_small) -> None:
        """Benchmark resize with different quality modes."""

        def resize_all_qualities(img) -> list:
            """Resize image with all quality modes in one benchmark."""
            results = []
            for quality in ["low", "medium", "high"]:
                runner = ImageToIcoRunner(input_path=sample_image_small, quality=quality)
                resized = runner._resize_for_icon(img, 64)
                results.append((quality, resized.width))
            return results

        with Image.open(str(sample_image_small)) as img:
            results = benchmark(resize_all_qualities, img)

            # Verify all quality modes produced correct results
            for _quality, width in results:
                assert width == 64

    @pytest.mark.benchmark
    def test_multisize_ico_creation(self, benchmark, sample_image_small, tmp_path) -> None:
        """Benchmark multisize ICO creation."""
        runner = ImageToIcoRunner(input_path=sample_image_small)

        # Prepare test images
        sizes = [16, 32, 64, 128]
        icon_images = []

        with Image.open(str(sample_image_small)) as img:
            for size in sizes:
                resized = runner._resize_for_icon(img, size)
                icon_images.append(resized)

        output_file = tmp_path / "multisize.ico"

        # Benchmark the creation
        benchmark(runner._create_genuine_multisize_ico, icon_images, sizes, output_file)

        assert output_file.exists()


class TestBatchConversionBenchmark:
    """Benchmarks for batch directory conversion."""

    @pytest.fixture
    def image_directory(self, tmp_path) -> Path:
        """Create a directory with multiple test images."""
        input_dir = tmp_path / "input_images"
        input_dir.mkdir()

        # Create 10 test images
        for i in range(10):
            img = Image.new("RGB", (200, 200), color=(i * 25, 0, 0))
            img_path = input_dir / f"image_{i:02d}.png"
            img.save(img_path, "PNG")

        return input_dir

    @pytest.mark.benchmark
    def test_batch_conversion_10_images(self, benchmark, image_directory) -> None:
        """Benchmark batch conversion of 10 images."""
        runner = ImageToIcoRunner(input_path=image_directory, sizes={16, 32, 64})

        result = benchmark(runner.run)

        # Verify output was created
        output_dir = image_directory / "ico_output"
        assert output_dir.exists()
        ico_files = list(output_dir.glob("*.ico"))
        assert len(ico_files) == 10
        assert result is None

    @pytest.mark.slow
    @pytest.mark.benchmark
    def test_batch_conversion_stress(self, benchmark, tmp_path) -> None:
        """Stress test batch conversion with many images."""
        # Create 50 test images
        input_dir = tmp_path / "stress_images"
        input_dir.mkdir()

        for i in range(50):
            img = Image.new("RGB", (300, 300), color=(i * 5, i * 3, i * 2))
            img_path = input_dir / f"image_{i:02d}.png"
            img.save(img_path, "PNG")

        runner = ImageToIcoRunner(
            input_path=input_dir,
            sizes={16, 32, 64, 128},  # More sizes for stress testing
        )

        result = benchmark(runner.run)

        # Verify all conversions completed
        output_dir = input_dir / "ico_output"
        assert output_dir.exists()
        ico_files = list(output_dir.glob("*.ico"))
        assert len(ico_files) == 50
        assert result is None


class TestConfigOperationsBenchmark:
    """Benchmarks for configuration operations."""

    @pytest.mark.benchmark
    def test_config_initialization_performance(self, benchmark: Callable) -> None:
        """Benchmark ImageToIcoConfig initialization."""
        config = benchmark(ImageToIcoConfig)
        assert config.DEFAULT_SIZES is not None
        assert config.EXTENSIONS is not None

    @pytest.mark.benchmark
    def test_config_save_performance(self, benchmark, tmp_path) -> None:
        """Benchmark config save operation."""
        temp_config_file = tmp_path / "config.json"

        config = ImageToIcoConfig()

        # Mock CONFIG_FILE
        from unittest.mock import patch

        with patch("pytola_office.img2ico.cli.CONFIG_FILE", temp_config_file):
            benchmark(config.save)

        assert temp_config_file.exists()
