"""ProviderConfig Pydantic model and per-provider defaults.

Loaded by get_provider() in ai/__init__.py; populated by load_provider_config()
in services/ai_config.py.

This file is a pure data module — it does NOT import any provider class.
"""
from __future__ import annotations

from typing import Optional

from pydantic import BaseModel


class ProviderConfig(BaseModel):
    """Typed configuration for a single AI provider instance.

    Fields:
        provider_id: One of the keys in PROVIDER_DEFAULTS (e.g. "openai", "groq").
        api_key: Decrypted API key; empty string for local providers (Ollama, LMStudio).
        base_url: Override for the provider's base URL; None means use the default.
        model: Model name; empty string means use the default from PROVIDER_DEFAULTS.
        context_chars: Character budget for input truncation; 0 means use the default.
    """

    model_config = {"extra": "forbid"}

    provider_id: str
    api_key: str = ""
    base_url: Optional[str] = None
    model: str = ""
    context_chars: int = 0  # 0 means "unset — use PROVIDER_DEFAULTS in get_provider()"


# Named preset defaults for all 10 supported providers.
# Values are [ASSUMED] approximations based on well-known context window sizes.
# Admins can override all fields via the system_settings DB table (D-04).
PROVIDER_DEFAULTS: dict[str, dict] = {
    "openai": {
        "base_url": None,
        "model": "gpt-4o",
        "context_chars": 120_000,
    },
    "anthropic": {
        "base_url": None,
        "model": "claude-sonnet-4-6",
        "context_chars": 180_000,
    },
    "gemini": {
        "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
        "model": "gemini-2.0-flash",
        "context_chars": 800_000,
    },
    "groq": {
        "base_url": "https://api.groq.com/openai/v1",
        "model": "llama-3.3-70b-versatile",
        "context_chars": 128_000,
    },
    "xai": {
        "base_url": "https://api.x.ai/v1",
        "model": "grok-3-mini",
        "context_chars": 128_000,
    },
    "deepseek": {
        "base_url": "https://api.deepseek.com",
        "model": "deepseek-chat",
        "context_chars": 60_000,
    },
    "openrouter": {
        "base_url": "https://openrouter.ai/api/v1",
        "model": "anthropic/claude-3.5-sonnet",
        "context_chars": 180_000,
    },
    "mistral": {
        "base_url": "https://api.mistral.ai/v1",
        "model": "mistral-large-latest",
        "context_chars": 128_000,
    },
    "ollama": {
        "base_url": "http://host.docker.internal:11434/v1",
        "model": "llama3.2",
        "context_chars": 8_000,
    },
    "lmstudio": {
        "base_url": "http://host.docker.internal:1234/v1",
        "model": "qwen/qwen3.5-9b",
        "context_chars": 32_000,
    },
}

# Whether the provider honours response_format={"type": "json_object"}.
# Gemini's OpenAI-compat endpoint does NOT support the string form (D-02/D-03).
# LMStudio only accepts "json_schema" or "text" (not "json_object") — set False
# so GenericOpenAIProvider omits response_format and relies on parse_classification().
# Ollama accepts the parameter but some models ignore it — left True; the
# GenericOpenAIProvider always wraps the raw response with parse_classification().
SUPPORTS_JSON_MODE: dict[str, bool] = {
    "openai": True,
    "anthropic": True,
    "gemini": False,
    "groq": True,
    "xai": True,
    "deepseek": True,
    "openrouter": True,
    "mistral": True,
    "ollama": True,
    "lmstudio": False,
}
