"""Tests for optimization configuration."""

from __future__ import annotations

import pytest

from sagellm_backend.graph.config import OptimizationConfig


class TestOptimizationConfig:
    """Tests for OptimizationConfig."""

    def test_default_config(self) -> None:
        """Test default configuration."""
        config = OptimizationConfig()
        assert config.level == 1
        assert config.enabled_passes is None
        assert config.disabled_passes == []
        assert config.target_device == "cpu"
        assert config.max_iterations == 10
        assert config.validate_after_each_pass is False

    def test_custom_config(self) -> None:
        """Test custom configuration."""
        config = OptimizationConfig(
            level=2,
            target_device="cuda",
            max_iterations=20,
            validate_after_each_pass=True,
        )
        assert config.level == 2
        assert config.target_device == "cuda"
        assert config.max_iterations == 20
        assert config.validate_after_each_pass is True

    def test_invalid_level(self) -> None:
        """Test that invalid optimization level raises error."""
        with pytest.raises(ValueError, match="Invalid optimization level"):
            OptimizationConfig(level=5)

        with pytest.raises(ValueError, match="Invalid optimization level"):
            OptimizationConfig(level=-1)

    def test_invalid_max_iterations(self) -> None:
        """Test that invalid max_iterations raises error."""
        with pytest.raises(ValueError, match="Invalid max_iterations"):
            OptimizationConfig(max_iterations=0)

        with pytest.raises(ValueError, match="Invalid max_iterations"):
            OptimizationConfig(max_iterations=-5)

    def test_invalid_target_device(self) -> None:
        """Test that invalid target device raises error."""
        with pytest.raises(ValueError, match="Invalid target_device"):
            OptimizationConfig(target_device="invalid_device")

    def test_target_device_with_index(self) -> None:
        """Test target device with device index."""
        config = OptimizationConfig(target_device="cuda:0")
        assert config.target_device == "cuda:0"

    def test_default_cpu_config(self) -> None:
        """Test default_cpu() factory method."""
        config = OptimizationConfig.default_cpu()
        assert config.level == 1
        assert config.target_device == "cpu"
        assert config.backend_config["vectorization"] is True
        assert config.backend_config["loop_unrolling"] is True

    def test_default_cuda_config(self) -> None:
        """Test default_cuda() factory method."""
        config = OptimizationConfig.default_cuda()
        assert config.level == 2
        assert config.target_device == "cuda"
        assert config.backend_config["use_tensor_cores"] is True
        assert config.backend_config["use_flash_attention"] is True

    def test_aggressive_config(self) -> None:
        """Test aggressive() factory method."""
        config = OptimizationConfig.aggressive(target_device="cuda")
        assert config.level == 2
        assert config.target_device == "cuda"
        assert config.max_iterations == 20
        assert config.validate_after_each_pass is True

    def test_experimental_config(self) -> None:
        """Test experimental() factory method."""
        config = OptimizationConfig.experimental(target_device="ascend")
        assert config.level == 3
        assert config.target_device == "ascend"
        assert config.max_iterations == 30
        assert config.validate_after_each_pass is True

    def test_is_pass_enabled_default(self) -> None:
        """Test is_pass_enabled with default behavior."""
        config = OptimizationConfig()

        # When enabled_passes is None, use pass default
        assert config.is_pass_enabled("some_pass", pass_default=True) is True
        assert config.is_pass_enabled("some_pass", pass_default=False) is False

    def test_is_pass_enabled_explicit_list(self) -> None:
        """Test is_pass_enabled with explicit enabled_passes list."""
        config = OptimizationConfig(enabled_passes=["pass1", "pass2"])

        # Only passes in enabled_passes should be enabled
        assert config.is_pass_enabled("pass1", pass_default=False) is True
        assert config.is_pass_enabled("pass3", pass_default=True) is False

    def test_is_pass_enabled_disabled_list(self) -> None:
        """Test is_pass_enabled with disabled_passes list."""
        config = OptimizationConfig(disabled_passes=["pass1"])

        # Passes in disabled_passes should be disabled
        assert config.is_pass_enabled("pass1", pass_default=True) is False
        assert config.is_pass_enabled("pass2", pass_default=True) is True

    def test_is_pass_enabled_priority(self) -> None:
        """Test that disabled_passes overrides enabled_passes."""
        config = OptimizationConfig(
            enabled_passes=["pass1", "pass2"],
            disabled_passes=["pass1"],
        )

        # pass1 is both enabled and disabled -> disabled wins
        assert config.is_pass_enabled("pass1", pass_default=True) is False
        assert config.is_pass_enabled("pass2", pass_default=True) is True

    def test_get_pass_config(self) -> None:
        """Test getting pass-specific configuration."""
        config = OptimizationConfig(
            pass_configs={
                "pass1": {"threshold": 0.5, "enabled": True},
                "pass2": {"max_depth": 10},
            }
        )

        pass1_config = config.get_pass_config("pass1")
        assert pass1_config["threshold"] == 0.5
        assert pass1_config["enabled"] is True

        # Non-existent pass config should return empty dict
        pass3_config = config.get_pass_config("pass3")
        assert pass3_config == {}

    def test_backend_config(self) -> None:
        """Test backend-specific configuration."""
        config = OptimizationConfig(
            backend_config={
                "use_tensor_cores": True,
                "kernel_fusion": False,
            }
        )

        assert config.backend_config["use_tensor_cores"] is True
        assert config.backend_config["kernel_fusion"] is False
