"""Tests for quber.agents.factory module (non-PydanticAI components)."""

import os
from unittest.mock import patch

from quber.agents.factory import AgentFactory, ModelConfig, ModelProvider


def test_model_provider_enum_values():
    """Test ModelProvider enum has expected values."""
    assert ModelProvider.ANTHROPIC.value == "anthropic"
    assert ModelProvider.OPENAI.value == "openai"
    assert ModelProvider.GROQ.value == "groq"
    assert ModelProvider.GEMINI.value == "gemini"
    assert ModelProvider.VERTEXAI.value == "vertexai"
    assert ModelProvider.BEDROCK.value == "bedrock"
    assert ModelProvider.OLLAMA.value == "ollama"


def test_model_config_default_models():
    """Test ModelConfig has default models for each provider."""
    assert ModelProvider.ANTHROPIC in ModelConfig.DEFAULT_MODELS
    assert ModelProvider.OPENAI in ModelConfig.DEFAULT_MODELS
    assert ModelProvider.GROQ in ModelConfig.DEFAULT_MODELS
    assert ModelProvider.GEMINI in ModelConfig.DEFAULT_MODELS

    assert ModelConfig.DEFAULT_MODELS[ModelProvider.ANTHROPIC] == "claude-haiku-4-5"
    assert ModelConfig.DEFAULT_MODELS[ModelProvider.OPENAI] == "gpt-4.1-mini"


def test_model_config_api_key_vars():
    """Test ModelConfig has API key environment variable names."""
    assert ModelConfig.API_KEY_VARS[ModelProvider.ANTHROPIC] == "ANTHROPIC_API_KEY"
    assert ModelConfig.API_KEY_VARS[ModelProvider.OPENAI] == "OPENAI_API_KEY"
    assert ModelConfig.API_KEY_VARS[ModelProvider.GROQ] == "GROQ_API_KEY"
    assert ModelConfig.API_KEY_VARS[ModelProvider.OLLAMA] is None


def test_model_config_get_known_models_from_registry():
    """get_known_models sources names from pydantic-ai's registry, grouped by provider."""
    models = ModelConfig.get_known_models()

    # Anthropic is always in the registry; names come back with the prefix stripped.
    assert "anthropic" in models
    assert any(name.startswith("claude") for name in models["anthropic"])
    assert all(":" not in name for name in models["anthropic"])


def test_model_config_get_known_models_maps_gemini_to_google():
    """Gemini resolves via the registry's 'google' prefix, not the literal 'gemini'.

    Guards the prefix mapping: filtering the registry by the bare provider value
    would return nothing for Gemini, since the registry groups it under 'google'.
    """
    models = ModelConfig.get_known_models()

    assert "gemini" in models
    assert any(name.startswith("gemini") for name in models["gemini"])


def test_default_models_are_registry_valid():
    """Every non-local default must be a real model id in pydantic-ai's registry.

    Guards against a hardcoded default silently going invalid the way
    gemini-1.5-flash did. Ollama has no registry prefix (it is local), so it is
    skipped.
    """
    from pydantic_ai.models import known_model_names

    names = set(known_model_names())
    for provider, model in ModelConfig.DEFAULT_MODELS.items():
        prefix = ModelConfig.REGISTRY_PREFIXES.get(provider)
        if prefix is None:  # Ollama: local, not carried in the registry.
            continue
        assert f"{prefix}:{model}" in names, f"default {model!r} for {provider} not in registry"


def test_agent_factory_init_defaults():
    """Test AgentFactory initialization with defaults."""
    with patch.dict(os.environ, {}, clear=True):
        factory = AgentFactory(enable_logfire=False)

        assert factory.enable_logfire is False
        assert factory.logfire_configured is False


def test_agent_factory_init_without_logfire():
    """Test AgentFactory initialization without logfire."""
    factory = AgentFactory(enable_logfire=False)

    assert factory.logfire_configured is False


@patch.dict(os.environ, {}, clear=True)
def test_agent_factorydetect_provider_no_keys():
    """Test provider detection with no API keys."""
    factory = AgentFactory(enable_logfire=False)

    provider = factory.detect_provider()

    assert provider is None


@patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key"})
def test_agent_factorydetect_provider_anthropic():
    """Test provider detection with Anthropic key."""
    factory = AgentFactory(enable_logfire=False)

    provider = factory.detect_provider()

    assert provider == ModelProvider.ANTHROPIC


@patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}, clear=True)
def test_agent_factorydetect_provider_openai():
    """Test provider detection with OpenAI key."""
    factory = AgentFactory(enable_logfire=False)

    provider = factory.detect_provider()

    assert provider == ModelProvider.OPENAI


@patch.dict(os.environ, {"ANTHROPIC_API_KEY": "key1", "OPENAI_API_KEY": "key2"})
def test_agent_factorydetect_provider_priority():
    """Test provider detection respects priority order."""
    factory = AgentFactory(enable_logfire=False)

    provider = factory.detect_provider()

    assert provider == ModelProvider.ANTHROPIC


def test_agent_factoryformat_model_string_anthropic():
    """Test formatting model string for Anthropic."""
    factory = AgentFactory(enable_logfire=False)

    result = factory.format_model_string(ModelProvider.ANTHROPIC, "claude-3-5-sonnet-latest")

    assert result == "claude-3-5-sonnet-latest"


def test_agent_factoryformat_model_string_anthropic_with_prefix():
    """Test formatting model string for Anthropic with existing prefix."""
    factory = AgentFactory(enable_logfire=False)

    result = factory.format_model_string(ModelProvider.ANTHROPIC, "anthropic:claude-3-5-sonnet-latest")

    assert result == "anthropic:claude-3-5-sonnet-latest"


def test_agent_factoryformat_model_string_openai():
    """Test formatting model string for OpenAI."""
    factory = AgentFactory(enable_logfire=False)

    result = factory.format_model_string(ModelProvider.OPENAI, "gpt-4o")

    assert result == "openai:gpt-4o"


def test_agent_factoryformat_model_string_groq():
    """Test formatting model string for Groq."""
    factory = AgentFactory(enable_logfire=False)

    result = factory.format_model_string(ModelProvider.GROQ, "llama-3.1-8b-instant")

    assert result == "groq:llama-3.1-8b-instant"


def test_agent_factoryformat_model_string_gemini():
    """Test formatting model string for Gemini."""
    factory = AgentFactory(enable_logfire=False)

    result = factory.format_model_string(ModelProvider.GEMINI, "gemini-1.5-flash")

    assert result == "gemini:gemini-1.5-flash"


def test_agent_factory_list_available_models_all():
    """Test listing all available models."""
    factory = AgentFactory(enable_logfire=False)

    with patch.object(ModelConfig, "get_known_models", return_value={}):
        models = factory.list_available_models()

        assert isinstance(models, dict)
        assert "anthropic" in models
        assert "openai" in models
        assert "groq" in models


def test_agent_factory_list_available_models_specific_provider():
    """Test listing models for specific provider."""
    factory = AgentFactory(enable_logfire=False)

    with patch.object(ModelConfig, "get_known_models", return_value={}):
        models = factory.list_available_models(provider=ModelProvider.ANTHROPIC)

        assert "anthropic" in models
        assert len(models) == 1


def test_agent_factory_list_available_models_with_known_models():
    """Test listing models when known_models are available."""
    factory = AgentFactory(enable_logfire=False)

    mock_known_models = {
        "anthropic": ["claude-3-5-sonnet-latest", "claude-3-5-haiku-latest"],
        "openai": ["gpt-4o", "gpt-4o-mini"],
    }

    with patch.object(ModelConfig, "get_known_models", return_value=mock_known_models):
        models = factory.list_available_models(provider=ModelProvider.ANTHROPIC)

        assert models["anthropic"] == ["claude-3-5-sonnet-latest", "claude-3-5-haiku-latest"]


@patch.dict(os.environ, {}, clear=True)
def test_agent_factory_get_available_providers_none():
    """Test getting available providers with no API keys."""
    factory = AgentFactory(enable_logfire=False)

    providers = factory.get_available_providers()

    assert ModelProvider.OLLAMA.value in providers
    assert ModelProvider.ANTHROPIC.value not in providers


@patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key"})
def test_agent_factory_get_available_providers_anthropic():
    """Test getting available providers with Anthropic key."""
    factory = AgentFactory(enable_logfire=False)

    providers = factory.get_available_providers()

    assert ModelProvider.ANTHROPIC.value in providers
    assert ModelProvider.OLLAMA.value in providers


@patch.dict(os.environ, {"ANTHROPIC_API_KEY": "key1", "OPENAI_API_KEY": "key2"})
def test_agent_factory_get_available_providers_multiple():
    """Test getting available providers with multiple keys."""
    factory = AgentFactory(enable_logfire=False)

    providers = factory.get_available_providers()

    assert ModelProvider.ANTHROPIC.value in providers
    assert ModelProvider.OPENAI.value in providers
    assert ModelProvider.OLLAMA.value in providers


def test_model_provider_enum_iteration():
    """Test that we can iterate over ModelProvider enum."""
    providers = list(ModelProvider)

    assert len(providers) == 12
    assert ModelProvider.ANTHROPIC in providers
    assert ModelProvider.OLLAMA in providers
    assert ModelProvider.XAI in providers


def test_model_config_all_providers_have_defaults():
    """Test that all providers have default models configured."""
    for provider in ModelProvider:
        assert provider in ModelConfig.DEFAULT_MODELS
        assert isinstance(ModelConfig.DEFAULT_MODELS[provider], str)
        assert len(ModelConfig.DEFAULT_MODELS[provider]) > 0


def test_model_config_all_providers_have_api_key_vars():
    """Test that all providers have API key variable mappings."""
    for provider in ModelProvider:
        assert provider in ModelConfig.API_KEY_VARS
        api_key_var = ModelConfig.API_KEY_VARS[provider]
        assert api_key_var is None or isinstance(api_key_var, str)
