"""
Unit tests for Routing Configuration.
[AC-AISVC-RES-01~15] Tests for strategy routing configuration models.
"""

import pytest

from app.services.retrieval.routing_config import (
    RagRuntimeMode,
    StrategyType,
    RoutingConfig,
    StrategyContext,
    StrategyResult,
)


class TestStrategyType:
    """[AC-AISVC-RES-01,02] Tests for StrategyType enum."""

    def test_strategy_type_default(self):
        """[AC-AISVC-RES-01] Default strategy type should exist."""
        assert StrategyType.DEFAULT.value == "default"

    def test_strategy_type_enhanced(self):
        """[AC-AISVC-RES-02] Enhanced strategy type should exist."""
        assert StrategyType.ENHANCED.value == "enhanced"

    def test_strategy_type_from_string(self):
        """Should create StrategyType from string."""
        assert StrategyType("default") == StrategyType.DEFAULT
        assert StrategyType("enhanced") == StrategyType.ENHANCED


class TestRagRuntimeMode:
    """[AC-AISVC-RES-09,10,11] Tests for RagRuntimeMode enum."""

    def test_mode_direct(self):
        """[AC-AISVC-RES-09] Direct mode should exist."""
        assert RagRuntimeMode.DIRECT.value == "direct"

    def test_mode_react(self):
        """[AC-AISVC-RES-10] React mode should exist."""
        assert RagRuntimeMode.REACT.value == "react"

    def test_mode_auto(self):
        """[AC-AISVC-RES-11] Auto mode should exist."""
        assert RagRuntimeMode.AUTO.value == "auto"

    def test_mode_from_string(self):
        """Should create RagRuntimeMode from string."""
        assert RagRuntimeMode("direct") == RagRuntimeMode.DIRECT
        assert RagRuntimeMode("react") == RagRuntimeMode.REACT
        assert RagRuntimeMode("auto") == RagRuntimeMode.AUTO


class TestRoutingConfig:
    """[AC-AISVC-RES-01~15] Tests for RoutingConfig."""

    def test_default_config(self):
        """[AC-AISVC-RES-01] Default config should use default strategy and auto mode."""
        config = RoutingConfig()

        assert config.enabled is True
        assert config.strategy == StrategyType.DEFAULT
        assert config.rag_runtime_mode == RagRuntimeMode.AUTO
        assert config.grayscale_percentage == 0.0
        assert config.grayscale_allowlist == []

    def test_config_with_custom_values(self):
        """[AC-AISVC-RES-02,03] Config should accept custom values."""
        config = RoutingConfig(
            enabled=False,
            strategy=StrategyType.ENHANCED,
            rag_runtime_mode=RagRuntimeMode.REACT,
            grayscale_percentage=0.3,
            grayscale_allowlist=["tenant_a", "tenant_b"],
        )

        assert config.enabled is False
        assert config.strategy == StrategyType.ENHANCED
        assert config.rag_runtime_mode == RagRuntimeMode.REACT
        assert config.grayscale_percentage == 0.3
        assert "tenant_a" in config.grayscale_allowlist

    def test_should_use_enhanced_strategy_default(self):
        """[AC-AISVC-RES-01] Default strategy should not use enhanced."""
        config = RoutingConfig()

        assert config.should_use_enhanced_strategy("tenant_a") is False

    def test_should_use_enhanced_strategy_explicit_enhanced(self):
        """[AC-AISVC-RES-02] Explicit enhanced strategy should use enhanced for all tenants."""
        config = RoutingConfig(strategy=StrategyType.ENHANCED)

        assert config.should_use_enhanced_strategy("tenant_a") is True
        assert config.should_use_enhanced_strategy("tenant_b") is True
        assert config.should_use_enhanced_strategy(None) is True

    def test_should_fallback_direct_to_react_disabled(self):
        """[AC-AISVC-RES-14] Fallback should be disabled when configured."""
        config = RoutingConfig(direct_fallback_on_low_confidence=False)

        assert config.should_fallback_direct_to_react(0.1) is False
        assert config.should_fallback_direct_to_react(0.0) is False

    def test_should_fallback_direct_to_react_enabled(self):
        """[AC-AISVC-RES-14] Fallback should trigger on low confidence."""
        config = RoutingConfig(
            direct_fallback_on_low_confidence=True,
            direct_fallback_confidence_threshold=0.4,
        )

        assert config.should_fallback_direct_to_react(0.3) is True
        assert config.should_fallback_direct_to_react(0.4) is False
        assert config.should_fallback_direct_to_react(0.5) is False

    def test_should_trigger_react_in_auto_mode_low_confidence(self):
        """[AC-AISVC-RES-12] Low confidence should trigger react in auto mode."""
        config = RoutingConfig(
            react_trigger_confidence_threshold=0.6,
        )

        assert config.should_trigger_react_in_auto_mode(
            confidence=0.5, complexity_score=0.3
        ) is True
        assert config.should_trigger_react_in_auto_mode(
            confidence=0.7, complexity_score=0.3
        ) is False

    def test_should_trigger_react_in_auto_mode_high_complexity(self):
        """[AC-AISVC-RES-13] High complexity should trigger react in auto mode."""
        config = RoutingConfig(
            react_trigger_complexity_score=0.5,
        )

        assert config.should_trigger_react_in_auto_mode(
            confidence=0.8, complexity_score=0.6
        ) is True
        assert config.should_trigger_react_in_auto_mode(
            confidence=0.8, complexity_score=0.4
        ) is False

    def test_validate_valid_config(self):
        """[AC-AISVC-RES-06] Valid config should pass validation."""
        config = RoutingConfig()

        is_valid, errors = config.validate()

        assert is_valid is True
        assert len(errors) == 0

    def test_validate_invalid_grayscale_percentage(self):
        """[AC-AISVC-RES-06] Invalid grayscale percentage should fail validation."""
        config = RoutingConfig(grayscale_percentage=1.5)

        is_valid, errors = config.validate()

        assert is_valid is False
        assert any("grayscale_percentage" in e for e in errors)

    def test_validate_invalid_confidence_threshold(self):
        """[AC-AISVC-RES-06] Invalid confidence threshold should fail validation."""
        config = RoutingConfig(react_trigger_confidence_threshold=1.5)

        is_valid, errors = config.validate()

        assert is_valid is False
        assert any("react_trigger_confidence_threshold" in e for e in errors)

    def test_validate_invalid_react_max_steps(self):
        """[AC-AISVC-RES-06] Invalid react max steps should fail validation."""
        config = RoutingConfig(react_max_steps=2)

        is_valid, errors = config.validate()

        assert is_valid is False
        assert any("react_max_steps" in e for e in errors)

    def test_validate_invalid_performance_budget(self):
        """[AC-AISVC-RES-06] Invalid performance budget should fail validation."""
        config = RoutingConfig(performance_budget_ms=500)

        is_valid, errors = config.validate()

        assert is_valid is False
        assert any("performance_budget_ms" in e for e in errors)


class TestStrategyContext:
    """[AC-AISVC-RES-01~15] Tests for StrategyContext."""

    def test_context_creation(self):
        """Should create context with all fields."""
        ctx = StrategyContext(
            tenant_id="tenant_a",
            query="Test query",
            metadata_filter={"category": "product"},
            metadata_confidence=0.8,
            complexity_score=0.3,
            kb_ids=["kb_1", "kb_2"],
            top_k=10,
        )

        assert ctx.tenant_id == "tenant_a"
        assert ctx.query == "Test query"
        assert ctx.metadata_filter == {"category": "product"}
        assert ctx.metadata_confidence == 0.8
        assert ctx.complexity_score == 0.3
        assert ctx.kb_ids == ["kb_1", "kb_2"]
        assert ctx.top_k == 10

    def test_context_minimal(self):
        """Should create context with minimal fields."""
        ctx = StrategyContext(tenant_id="tenant_a", query="Test query")

        assert ctx.tenant_id == "tenant_a"
        assert ctx.query == "Test query"
        assert ctx.metadata_filter is None
        assert ctx.metadata_confidence == 1.0
        assert ctx.complexity_score == 0.0
        assert ctx.kb_ids is None
        assert ctx.top_k == 5


class TestStrategyResult:
    """[AC-AISVC-RES-01,02] Tests for StrategyResult."""

    def test_result_creation(self):
        """Should create result with all fields."""
        result = StrategyResult(
            strategy=StrategyType.ENHANCED,
            mode=RagRuntimeMode.REACT,
            should_fallback=True,
            fallback_reason="Low confidence",
            diagnostics={"key": "value"},
        )

        assert result.strategy == StrategyType.ENHANCED
        assert result.mode == RagRuntimeMode.REACT
        assert result.should_fallback is True
        assert result.fallback_reason == "Low confidence"
        assert result.diagnostics == {"key": "value"}

    def test_result_defaults(self):
        """Should create result with default values."""
        result = StrategyResult(
            strategy=StrategyType.DEFAULT,
            mode=RagRuntimeMode.AUTO,
        )

        assert result.should_fallback is False
        assert result.fallback_reason is None
        assert result.diagnostics == {}
