"""Custom OpenAI-compatible endpoint provider for Local Deep Research."""

from loguru import logger

from ....config.thread_settings import get_setting_from_snapshot
from ....security.log_sanitizer import redact_secrets
from ....utilities.url_utils import normalize_url
from ..openai_base import OpenAICompatibleProvider


class CustomOpenAIEndpointProvider(OpenAICompatibleProvider):
    """Custom OpenAI-compatible endpoint provider.

    This provider allows users to connect to any OpenAI-compatible API endpoint
    by specifying a custom URL in the settings.
    """

    provider_name = "OpenAI-Compatible Endpoint"
    api_key_setting = "llm.openai_endpoint.api_key"
    # Many OpenAI-compatible servers (vLLM, local LLMs, etc.) don't require
    # auth. Optional flag lets the resolver fall back to a placeholder when
    # no key is configured, instead of raising at LLM construction time.
    api_key_optional = True
    url_setting = "llm.openai_endpoint.url"  # type: ignore[assignment]  # Settings key for URL
    default_base_url = "https://api.openai.com/v1"
    default_model = ""  # User must explicitly pick a model — no silent fallback

    # Metadata for auto-discovery
    provider_key = "OPENAI_ENDPOINT"
    company_name = "OpenAI-Compatible"
    is_cloud = None  # Unknown — could be local or cloud

    @classmethod
    def requires_auth_for_models(cls):
        """Custom endpoints may or may not require authentication for listing models.

        Many OpenAI-compatible servers (vLLM, local LLMs, etc.) don't require
        authentication. Return False to allow model listing without an API key.
        If the endpoint requires auth, the OpenAI client will raise an error.
        """
        return False

    @classmethod
    def is_available(cls, settings_snapshot=None):
        """Custom endpoints are available with either an API key or a custom URL.

        Unlike cloud-only providers, custom endpoints support keyless local
        servers (vLLM, text-generation-webui, etc.). The provider is
        considered configured when the user has set either an API key or a
        URL that differs from the default OpenAI endpoint.
        """
        api_key = None
        try:
            api_key = get_setting_from_snapshot(
                cls.api_key_setting,
                default=None,
                settings_snapshot=settings_snapshot,
            )
            if api_key and str(api_key).strip():
                return True
        except Exception as e:
            # Drop exc_info — the cause chain may embed the api_key value
            # if a settings-layer error message surfaces it. Interpolate
            # a redacted exception message instead.
            safe_msg = redact_secrets(str(e), api_key)
            logger.debug(f"Error checking provider availability: {safe_msg}")

        try:
            custom_url = get_setting_from_snapshot(
                cls.url_setting,
                default=None,
                settings_snapshot=settings_snapshot,
            )
            if custom_url and str(custom_url).strip():
                normalized = normalize_url(str(custom_url).strip())
                if normalized.rstrip("/") != cls.default_base_url.rstrip("/"):
                    return True
        except Exception:
            logger.debug(
                f"Error reading URL setting '{cls.url_setting}'",
                exc_info=True,
            )

        return False

    @classmethod
    def create_llm(cls, model_name=None, temperature=0.7, **kwargs):
        """Override to get URL from settings."""
        settings_snapshot = kwargs.get("settings_snapshot")

        # Keyless construction is supported (vLLM, text-generation-webui),
        # but a key-requiring endpoint (e.g. OpenRouter) fails with an
        # opaque upstream 401 — warn so the misconfiguration is traceable.
        if cls.resolve_api_key(settings_snapshot) is None:
            logger.warning(
                "No API key configured for openai_endpoint provider; "
                "proceeding with a placeholder. If your endpoint requires "
                "an API key, set llm.openai_endpoint.api_key in settings."
            )

        # Get custom endpoint URL from settings
        custom_url = get_setting_from_snapshot(
            "llm.openai_endpoint.url",
            default=cls.default_base_url,
            settings_snapshot=settings_snapshot,
        )

        # Normalize and pass the custom URL to parent implementation
        kwargs["base_url"] = (
            normalize_url(custom_url) if custom_url else cls.default_base_url
        )

        # Opt-in token usage on streamed responses. Off by default because
        # some OpenAI-compatible gateways reject stream_options with a 400
        # (e.g. xAI, Databricks AI Gateway, Azure "on your data"), which
        # would break the call entirely — worse than missing token counts.
        stream_usage = get_setting_from_snapshot(
            "llm.openai_endpoint.stream_usage",
            default=False,
            settings_snapshot=settings_snapshot,
        )
        if stream_usage:
            kwargs["stream_usage"] = True

        return super().create_llm(model_name, temperature, **kwargs)
