"""Provider credentials and per-provider base-URL resolution.

Loads ``.env`` (via pydantic-settings) and exposes the API key / base URL for a
given provider. Keeping this in one place means the factory and the live smoke
test agree on exactly how a provider is reached. Keys are pydantic fields (not
raw ``os.getenv``) so ``.env`` is honored and tests can inject values directly.
"""

from __future__ import annotations

from pydantic import AliasChoices, Field
from pydantic_settings import BaseSettings, SettingsConfigDict

from pentestgpt_legacy.llm.registry import PROVIDERS, ProviderInfo

# provider key -> the settings attribute holding its API key (None => no key)
_KEY_FIELD: dict[str, str | None] = {
    "openai": "openai_api_key",
    "anthropic": "anthropic_api_key",
    "gemini": "gemini_api_key",
    "deepseek": "deepseek_api_key",
    "xai": "grok_api_key",
    "qwen": "qwen_api_key",
    "moonshot": "kimi_api_key",
    "ollama": None,
}


class LLMSettings(BaseSettings):
    """Environment-backed credentials. All optional — only what you use matters."""

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    openai_api_key: str | None = None
    anthropic_api_key: str | None = None
    gemini_api_key: str | None = Field(
        default=None,
        validation_alias=AliasChoices("GEMINI_API_KEY", "GOOGLE_API_KEY"),
    )
    deepseek_api_key: str | None = None
    grok_api_key: str | None = Field(
        default=None, validation_alias=AliasChoices("GROK_API_KEY", "XAI_API_KEY")
    )
    qwen_api_key: str | None = Field(
        default=None, validation_alias=AliasChoices("QWEN_API_KEY", "DASHSCOPE_API_KEY")
    )
    kimi_api_key: str | None = Field(
        default=None, validation_alias=AliasChoices("KIMI_API_KEY", "MOONSHOT_API_KEY")
    )

    # Optional per-provider base-URL overrides (defaults come from the registry).
    openai_base_url: str | None = None
    deepseek_base_url: str | None = None
    xai_base_url: str | None = None
    qwen_base_url: str | None = None
    moonshot_base_url: str | None = None
    ollama_base_url: str | None = None

    def api_key_for(self, provider: ProviderInfo) -> str | None:
        """Return the configured API key for ``provider`` (or ``None``)."""
        field = _KEY_FIELD.get(provider.key)
        if field is None:
            return None
        value = getattr(self, field, None)
        return str(value) if value else None

    def base_url_for(self, provider: ProviderInfo) -> str | None:
        """Return the base URL: explicit override, else the registry default."""
        override = getattr(self, f"{provider.key}_base_url", None)
        if override:
            return str(override)
        return provider.base_url


_settings: LLMSettings | None = None


def get_settings() -> LLMSettings:
    """Process-wide singleton settings (reads ``.env`` + environment once)."""
    global _settings
    if _settings is None:
        _settings = LLMSettings()
    return _settings


def configured_providers() -> list[str]:
    """Provider keys that currently have a usable key (or need none, e.g. Ollama)."""
    settings = get_settings()
    return [
        key
        for key, info in PROVIDERS.items()
        if not info.requires_key or settings.api_key_for(info)
    ]
