"""Tests for pure logic in the LLM rate limit wrapper.

Tests cover:
- _check_if_local_model: provider name matching, base_url localhost detection
- _get_rate_limit_key: provider-url-model composite key building, URL
  parsing, model name cleaning
"""

import types

import pytest

from local_deep_research.web_search_engines.rate_limiting.llm.wrapper import (
    create_rate_limited_llm_wrapper,
)


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _make_llm(**attrs):
    """Build a simple namespace that acts as an LLM with given attributes."""
    return types.SimpleNamespace(**attrs)


def _wrapper(llm=None, provider=None):
    """Build a RateLimitedLLMWrapper (rate limiting disabled by default)."""
    if llm is None:
        llm = _make_llm()
    return create_rate_limited_llm_wrapper(llm, provider=provider)


# ===================================================================
# _check_if_local_model
# ===================================================================


class TestCheckIfLocalModel:
    """Tests for RateLimitedLLMWrapper._check_if_local_model()."""

    # -- provider name matching ----------------------------------------

    @pytest.mark.parametrize(
        "provider",
        ["ollama", "lmstudio", "llamacpp", "local", "none"],
    )
    def test_local_providers_detected(self, provider):
        w = _wrapper(provider=provider)
        assert w._check_if_local_model() is True

    @pytest.mark.parametrize(
        "provider",
        ["Ollama", "LMSTUDIO", "LlamaCpp", "LOCAL", "NONE"],
    )
    def test_local_providers_case_insensitive(self, provider):
        w = _wrapper(provider=provider)
        assert w._check_if_local_model() is True

    @pytest.mark.parametrize("provider", ["openai", "anthropic", "google"])
    def test_cloud_providers_not_local(self, provider):
        w = _wrapper(provider=provider)
        assert w._check_if_local_model() is False

    def test_none_provider_with_remote_url(self):
        llm = _make_llm(base_url="https://api.openai.com/v1")
        w = _wrapper(llm=llm, provider=None)
        assert w._check_if_local_model() is False

    # -- base_url localhost detection ----------------------------------

    def test_localhost_url_detected(self):
        llm = _make_llm(base_url="http://localhost:11434")
        w = _wrapper(llm=llm, provider="unknown")
        assert w._check_if_local_model() is True

    def test_127_0_0_1_url_detected(self):
        llm = _make_llm(base_url="http://127.0.0.1:8000")
        w = _wrapper(llm=llm, provider="unknown")
        assert w._check_if_local_model() is True

    def test_0_0_0_0_url_detected(self):
        llm = _make_llm(base_url="http://0.0.0.0:5000")
        w = _wrapper(llm=llm, provider="unknown")
        assert w._check_if_local_model() is True

    def test_remote_url_not_detected(self):
        llm = _make_llm(base_url="https://api.anthropic.com")
        w = _wrapper(llm=llm, provider="unknown")
        assert w._check_if_local_model() is False

    def test_no_base_url_attribute(self):
        llm = _make_llm()
        w = _wrapper(llm=llm, provider="unknown")
        assert w._check_if_local_model() is False


# ===================================================================
# _get_rate_limit_key
# ===================================================================


class TestGetRateLimitKey:
    """Tests for RateLimitedLLMWrapper._get_rate_limit_key()."""

    def test_basic_key_structure(self):
        llm = _make_llm(
            base_url="https://api.openai.com/v1",
            model_name="gpt-4",
        )
        w = _wrapper(llm=llm, provider="openai")
        key = w._get_rate_limit_key()
        assert key == "openai-api.openai.com-gpt-4"

    def test_unknown_provider_fallback(self):
        llm = _make_llm(base_url="https://example.com", model_name="test")
        w = _wrapper(llm=llm, provider=None)
        key = w._get_rate_limit_key()
        assert key.startswith("unknown-")

    def test_unknown_url_fallback(self):
        llm = _make_llm(model_name="test-model")
        w = _wrapper(llm=llm, provider="openai")
        key = w._get_rate_limit_key()
        assert key == "openai-unknown-test-model"

    def test_unknown_model_fallback(self):
        llm = _make_llm(base_url="https://api.openai.com/v1")
        w = _wrapper(llm=llm, provider="openai")
        key = w._get_rate_limit_key()
        assert key == "openai-api.openai.com-unknown"

    def test_model_name_slashes_replaced(self):
        llm = _make_llm(model_name="meta/llama-3/70b")
        w = _wrapper(llm=llm, provider="ollama")
        key = w._get_rate_limit_key()
        assert "meta-llama-3-70b" in key

    def test_model_name_colons_replaced(self):
        llm = _make_llm(model_name="llama3:latest")
        w = _wrapper(llm=llm, provider="ollama")
        key = w._get_rate_limit_key()
        assert "llama3-latest" in key

    def test_model_attr_fallback_to_model(self):
        """Falls back from model_name to model attribute."""
        llm = _make_llm(model="claude-3-opus")
        w = _wrapper(llm=llm, provider="anthropic")
        key = w._get_rate_limit_key()
        assert "claude-3-opus" in key

    def test_url_trailing_slash_stripped(self):
        llm = _make_llm(
            base_url="https://api.openai.com/v1/",
            model_name="gpt-4",
        )
        w = _wrapper(llm=llm, provider="openai")
        key = w._get_rate_limit_key()
        # netloc is api.openai.com, path /v1/ is stripped to get netloc
        assert "api.openai.com" in key

    def test_client_base_url_fallback(self):
        """Falls back to _client.base_url when base_url absent."""
        client = types.SimpleNamespace(base_url="https://api.example.com")
        llm = _make_llm(_client=client, model_name="test")
        w = _wrapper(llm=llm, provider="custom")
        key = w._get_rate_limit_key()
        assert "api.example.com" in key

    def test_all_unknown(self):
        llm = _make_llm()
        w = _wrapper(llm=llm, provider=None)
        assert w._get_rate_limit_key() == "unknown-unknown-unknown"
