"""Edge-case tests for rate_limiting/llm/detection.py — provider-specific detection and retry parsing."""

from unittest.mock import Mock


def _make_exception(class_name, module, message):
    """Create an exception with a custom __class__.__module__."""
    cls = type(class_name, (Exception,), {"__module__": module})
    return cls(message)


class TestOpenAIModuleDetection:
    """Tests for OpenAI-specific module-based detection (line 52)."""

    def test_openai_module_ratelimiterror_type(self):
        """error.__class__.__module__ == 'openai' with RateLimitError type + 429."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            is_llm_rate_limit_error,
        )

        error = _make_exception("RateLimitError", "openai", "Error code: 429")
        assert is_llm_rate_limit_error(error) is True


class TestAnthropicModuleDetection:
    """Tests for Anthropic-specific module-based detection (line 58-64)."""

    def test_anthropic_module_rate_limit(self):
        """'anthropic' in module with rate_limit in message -> True."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            is_llm_rate_limit_error,
        )

        error = _make_exception(
            "RateLimitError", "anthropic.errors", "rate_limit exceeded"
        )
        assert is_llm_rate_limit_error(error) is True

    def test_anthropic_non_rate_limit_not_detected(self):
        """Anthropic auth error should NOT be detected as rate limit."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            is_llm_rate_limit_error,
        )

        error = _make_exception(
            "AuthenticationError",
            "anthropic.errors",
            "Invalid API key provided",
        )
        assert is_llm_rate_limit_error(error) is False


class TestErrorTypeNameDetection:
    """Tests for error type name detection (line 47)."""

    def test_quota_exceeded_error_type_name(self):
        """'quotaexceeded' in error_type for Google/Vertex errors."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            is_llm_rate_limit_error,
        )

        error = _make_exception(
            "QuotaExceededError",
            "google.api_core",
            "Quota exceeded for project",
        )
        assert is_llm_rate_limit_error(error) is True

    def test_429_in_message_without_response_attr(self):
        """Fallthrough to string matching when no HTTP response object."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            is_llm_rate_limit_error,
        )

        error = Exception("HTTP 429 Too Many Requests")
        assert not hasattr(error, "response") or error.response is None
        assert is_llm_rate_limit_error(error) is True


class TestExtractRetryAfterEdgeCases:
    """Tests for extract_retry_after edge cases."""

    def test_extract_retry_after_invalid_header(self):
        """Non-numeric Retry-After header (HTTP-date format) returns 0."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            extract_retry_after,
        )

        error = Mock()
        error.response = Mock()
        error.response.headers = {
            "Retry-After": "Thu, 01 Dec 2025 16:00:00 GMT"
        }
        result = extract_retry_after(error)
        assert result == 0

    def test_extract_retry_after_float_header(self):
        """Fractional '1.5' in Retry-After header."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            extract_retry_after,
        )

        error = Mock()
        error.response = Mock()
        error.response.headers = {"Retry-After": "1.5"}
        result = extract_retry_after(error)
        assert result == 1.5

    def test_extract_retry_after_retry_after_pattern(self):
        """'retry after 30 seconds' pattern (line 98)."""
        from local_deep_research.web_search_engines.rate_limiting.llm.detection import (
            extract_retry_after,
        )

        error = Exception("Please retry after 30 seconds")
        result = extract_retry_after(error)
        assert result == 30.0
