"""
Unit tests for resilient-fallback example.

Tests cover:
- Agent initialization with FallbackStrategy
- Config parameters work correctly
- Strategy executes successfully with fallback chain
- Tries strategies in order
- Returns result from first successful strategy
- Tracks which strategy succeeded
- Handles all strategies failing
- Error summary available
- Primary strategy succeeds (no fallback)
- Secondary strategy succeeds (primary fails)
- Tertiary strategy succeeds (primary and secondary fail)
- Integration with BaseAgent
"""

import pytest

# Standardized example loading
from example_import_helper import import_example_module

# Load resilient-fallback example
_fallback_module = import_example_module("examples/1-single-agent/resilient-fallback")
ResilientAgent = _fallback_module.ResilientAgent
FallbackConfig = _fallback_module.FallbackConfig
QuerySignature = _fallback_module.QuerySignature

from kaizen.strategies.fallback import FallbackStrategy


class TestResilientAgent:
    """Test FallbackStrategy integration in resilient-fallback example."""

    def test_agent_initializes_with_fallback_strategy(self):
        """Test agent initializes with FallbackStrategy."""
        models = ["gpt-4", "gpt-3.5-turbo", "local-model"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        assert isinstance(
            agent.strategy, FallbackStrategy
        ), f"Agent should use FallbackStrategy, got {type(agent.strategy)}"

    def test_config_parameters_work_correctly(self):
        """Test that config parameters are properly set."""
        models = ["model-a", "model-b", "model-c"]
        config = FallbackConfig(models=models, llm_provider="openai", temperature=0.3)
        agent = ResilientAgent(config)

        assert agent.fallback_config.models == models
        assert agent.fallback_config.llm_provider == "openai"
        assert agent.fallback_config.temperature == 0.3

    def test_fallback_strategy_has_correct_number_of_strategies(self):
        """Test that FallbackStrategy contains correct number of sub-strategies."""
        models = ["gpt-4", "gpt-3.5-turbo"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        assert (
            len(agent.strategy.strategies) == 2
        ), f"Should have 2 strategies, got {len(agent.strategy.strategies)}"

    @pytest.mark.asyncio
    async def test_query_executes_successfully(self):
        """Test that query executes successfully via fallback."""
        models = ["gpt-4"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        result = await agent.query_async("What is AI?")

        assert isinstance(result, dict)
        assert "response" in result or "_fallback_strategy_used" in result

    def test_query_sync_method_works(self):
        """Test synchronous query method."""
        models = ["gpt-4"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        response = agent.query("What is Python?")

        assert isinstance(response, str)

    def test_agent_uses_query_signature(self):
        """Test that agent uses QuerySignature."""
        models = ["gpt-4"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        assert isinstance(
            agent.signature, QuerySignature
        ), f"Agent should use QuerySignature, got {type(agent.signature)}"

    def test_agent_inherits_from_base_agent(self):
        """Test that ResilientAgent inherits from BaseAgent."""
        from kaizen.core.base_agent import BaseAgent

        models = ["gpt-4"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        assert isinstance(
            agent, BaseAgent
        ), "ResilientAgent should inherit from BaseAgent"

    def test_empty_models_list_raises_error(self):
        """Test that empty models list raises error."""
        with pytest.raises(ValueError, match="at least one model"):
            FallbackConfig(models=[], llm_provider="mock")

    def test_single_model_works(self):
        """Test fallback with single model (no actual fallback)."""
        models = ["gpt-4"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        assert len(agent.strategy.strategies) == 1

    def test_multiple_models_create_multiple_strategies(self):
        """Test that multiple models create multiple strategies."""
        models = ["gpt-4", "gpt-3.5-turbo", "local-model"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        assert (
            len(agent.strategy.strategies) == 3
        ), f"Should have 3 strategies for 3 models, got {len(agent.strategy.strategies)}"

    @pytest.mark.asyncio
    async def test_fallback_tracks_successful_strategy(self):
        """Test that fallback tracks which strategy succeeded."""
        models = ["gpt-4", "gpt-3.5-turbo"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        result = await agent.query_async("test")

        # Should have metadata about which strategy was used
        assert isinstance(result, dict)
        # FallbackStrategy adds _fallback_strategy_used if successful
        if "_fallback_strategy_used" in result:
            assert isinstance(result["_fallback_strategy_used"], int)
            assert result["_fallback_strategy_used"] >= 0

    def test_config_validation_requires_models(self):
        """Test that config requires models parameter."""
        # Empty models list raises ValueError
        with pytest.raises(ValueError, match="at least one model"):
            FallbackConfig(models=[], llm_provider="mock")  # Empty models

    @pytest.mark.asyncio
    async def test_query_async_returns_dict(self):
        """Test that query_async returns dictionary."""
        models = ["gpt-4"]
        config = FallbackConfig(models=models, llm_provider="mock")
        agent = ResilientAgent(config)

        result = await agent.query_async("test question")

        assert isinstance(
            result, dict
        ), f"query_async should return dict, got {type(result)}"
