"""
Behavioral tests for config/llm_config module.

Tests availability checks with snapshots, provider validation,
model/provider name cleaning, fallback model, and provider selection.
"""

import pytest


class TestApiKeyAvailabilityChecks:
    """Tests for is_*_available() functions with settings snapshots.

    These functions check bool(api_key) from the snapshot — the core
    logic is: present and non-empty → True, else → False.
    """

    def test_openai_available_with_api_key(self):
        from local_deep_research.config.llm_config import is_openai_available

        result = is_openai_available(
            settings_snapshot={"llm.openai.api_key": "sk-test"}
        )
        assert result is True

    def test_openai_unavailable_without_api_key(self):
        from local_deep_research.config.llm_config import is_openai_available

        assert is_openai_available(settings_snapshot={}) is False

    def test_openai_unavailable_with_empty_api_key(self):
        """Empty string API key is falsy — treated as missing."""
        from local_deep_research.config.llm_config import is_openai_available

        result = is_openai_available(
            settings_snapshot={"llm.openai.api_key": ""}
        )
        assert result is False

    def test_anthropic_available_with_api_key(self):
        from local_deep_research.config.llm_config import is_anthropic_available

        result = is_anthropic_available(
            settings_snapshot={"llm.anthropic.api_key": "sk-ant-test"}
        )
        assert result is True

    def test_anthropic_unavailable_without_api_key(self):
        from local_deep_research.config.llm_config import is_anthropic_available

        assert is_anthropic_available(settings_snapshot={}) is False

    def test_openai_endpoint_available_with_api_key(self):
        from local_deep_research.config.llm_config import (
            is_openai_endpoint_available,
        )

        result = is_openai_endpoint_available(
            settings_snapshot={"llm.openai_endpoint.api_key": "key123"}
        )
        assert result is True

    def test_openai_endpoint_unavailable_without_api_key(self):
        from local_deep_research.config.llm_config import (
            is_openai_endpoint_available,
        )

        assert is_openai_endpoint_available(settings_snapshot={}) is False


class TestProviderValidation:
    """Tests for provider validation in get_llm()."""

    def test_invalid_provider_raises_value_error(self):
        """get_llm raises ValueError for unknown provider name."""
        from local_deep_research.config.llm_config import get_llm

        with pytest.raises(ValueError, match="Invalid provider"):
            get_llm(provider="nonexistent_provider", settings_snapshot={})

    def test_error_message_lists_valid_providers(self):
        """ValueError message includes the VALID_PROVIDERS list."""
        from local_deep_research.config.llm_config import (
            VALID_PROVIDERS,
            get_llm,
        )

        with pytest.raises(ValueError) as exc_info:
            get_llm(provider="bad_provider", settings_snapshot={})
        for p in VALID_PROVIDERS:
            assert p in str(exc_info.value)


class TestModelAndProviderNameCleaning:
    """Tests for model_name and provider name cleaning in get_llm().

    get_llm strips quotes, whitespace, and lowercases the provider name
    before validation. Using provider='none' (valid, returns fallback).
    """

    def test_quoted_provider_name_cleaned(self):
        """Surrounding quotes are stripped: \"'none'\" → 'none'."""
        from local_deep_research.config.llm_config import get_llm

        result = get_llm(provider="'none'", settings_snapshot={})
        assert result is not None

    def test_whitespace_provider_name_cleaned(self):
        """Surrounding whitespace is stripped: '  none  ' → 'none'."""
        from local_deep_research.config.llm_config import get_llm

        result = get_llm(provider="  none  ", settings_snapshot={})
        assert result is not None

    def test_uppercase_provider_lowercased(self):
        """Provider name is lowercased: 'NONE' → 'none'."""
        from local_deep_research.config.llm_config import get_llm

        result = get_llm(provider="NONE", settings_snapshot={})
        assert result is not None

    def test_combined_quotes_whitespace_case_cleaning(self):
        """Combined cleaning: \"  'None'  \" → 'none'."""
        from local_deep_research.config.llm_config import get_llm

        result = get_llm(provider="  'None'  ", settings_snapshot={})
        assert result is not None


class TestFallbackModel:
    """Tests for get_fallback_model() function."""

    def test_returns_fake_list_chat_model(self):
        from langchain_core.language_models import FakeListChatModel

        from local_deep_research.config.llm_config import get_fallback_model

        result = get_fallback_model()
        assert isinstance(result, FakeListChatModel)

    def test_fallback_has_informative_response(self):
        """Fallback model's response tells user no providers are available."""
        from local_deep_research.config.llm_config import get_fallback_model

        result = get_fallback_model()
        assert len(result.responses) > 0
        assert "No language models" in result.responses[0]


class TestGetSelectedLlmProvider:
    """Tests for get_selected_llm_provider() function."""

    def test_returns_lowercase(self):
        """Provider value from snapshot is lowercased."""
        from local_deep_research.config.llm_config import (
            get_selected_llm_provider,
        )

        result = get_selected_llm_provider(
            settings_snapshot={"llm.provider": "OpenAI"}
        )
        assert result == "openai"

    def test_default_is_ollama(self):
        """Default provider is 'ollama' when not specified in snapshot."""
        from local_deep_research.config.llm_config import (
            get_selected_llm_provider,
        )

        result = get_selected_llm_provider(settings_snapshot={})
        assert result == "ollama"
