"""Registre des fournisseurs de modèles IA.

Deux catégories :

1. NO_KEY  : services qui tournent SANS que l'utilisateur ait à saisir une clé.
             Le serveur utilise son propre pool de clés (variable d'environnement).
             -> mis en avant dans la console.

2. USER_KEY : services qui nécessitent que l'utilisateur fournisse SA clé API.
             Groupés dans un menu déroulant "API EXT" + champ pour saisir la clé.

Tous les fournisseurs exposent une API compatible OpenAI  (/v1/chat/completions),
ce qui permet un routage uniforme dans le client HTTP.
"""

from dataclasses import dataclass, field
from typing import Optional


@dataclass(frozen=True)
class Provider:
    id: str
    name: str
    base_url: str                      # racine API compatible OpenAI
    env_key: str                       # nom de la variable d'env pour LA clé serveur
    needs_user_key: bool               # True => l'utilisateur doit fournir sa clé
    logo: str = ""                     # emoji/sigle pour l'UI
    models: tuple = ()                 # modèles gratuits par défaut (id:display)
    note: str = ""                     # infobulle d'aide


# ---------------------------------------------------------------------------
# 1) CATÉGORIE "SANS CLÉ" : le serveur détient la clé (pool interne)
#    L'utilisateur n'a RIEN à saisir. Mis en avant.
# ---------------------------------------------------------------------------
NO_KEY_PROVIDERS = (
    Provider(
        id="openrouter",
        name="OpenRouter (pool serveur)",
        base_url="https://openrouter.ai/api/v1",
        env_key="OPENROUTER_API_KEY",
        needs_user_key=False,
        logo="🔀",
        models=(
            ("deepseek/deepseek-v4-flash", "🐋 DeepSeek V4 Flash (quasi-gratuit)"),
            ("liquid/lfm-2.5-2.6b:free", "⚡ Liquid LFM 2.6B :free (~1 s)"),
            ("nvidia/nemotron-3-super-120b-a12b:free", "Nemotron Super 120B :free (~5 s)"),
            ("minimax/minimax-m3:free", "MiniMax M3 :free (~20 s)"),
            ("nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", "Nemotron nano 30B :free"),
            ("z-ai/glm-5.2:free", "GLM-5.2 :free (lent/saturé)"),
            ("google/gemma-4-31b-it:free", "Gemma 4 31B :free (lent/saturé)"),
        ),
        note="Modèles sans clé à saisir (pool serveur). Les :free sont gratuits ; DeepSeek est quasi-gratuit (facturation infime sur la clé serveur).",
    ),
)


# ---------------------------------------------------------------------------
# 2) CATÉGORIE "API EXTERNE (AVEC CLÉ)" : l'utilisateur fournit sa clé
#    Groupés dans un menu déroulant + champ "API EXT".
# ---------------------------------------------------------------------------
USER_KEY_PROVIDERS = (
    Provider(
        id="groq",
        name="Groq",
        base_url="https://api.groq.com/openai/v1",
        env_key="GROQ_API_KEY",
        needs_user_key=True,
        logo="⚡",
        models=(
            ("openai/gpt-oss-120b", "GPT-OSS 120B"),
            ("openai/gpt-oss-20b", "GPT-OSS 20B"),
            ("qwen/qwen3.6-27b", "Qwen3.6 27B"),
            ("gemma2-9b-it", "Gemma 2 9B"),
        ),
        note="Très rapide. Clé gratuite sur console.groq.com (sans carte bancaire). (llama-3.3-70b-versatile retiré le 16/08/26 → gpt-oss-120b)",
    ),
    Provider(
        id="gemini",
        name="Google Gemini",
        base_url="https://generativelanguage.googleapis.com/v1beta/openai",
        env_key="GEMINI_API_KEY",
        needs_user_key=True,
        logo="🅶",
        models=(
            ("gemini-2.5-flash", "Gemini 2.5 Flash"),
            ("gemini-2.0-flash", "Gemini 2.0 Flash"),
            ("gemini-1.5-flash", "Gemini 1.5 Flash"),
        ),
        note="Clé gratuite sur aistudio.google.com (pense à l'activer sur l'API génératrice).",
    ),
    Provider(
        id="nvidia",
        name="NVIDIA NIM",
        base_url="https://integrate.api.nvidia.com/v1",
        env_key="NVIDIA_API_KEY",
        needs_user_key=True,
        logo="🎮",
        models=(
            ("deepseek-ai/deepseek-r1", "DeepSeek R1"),
            ("meta/llama-3.3-70b-instruct", "Llama 3.3 70B"),
            ("moonshotai/kimi-k2-instruct", "Kimi K2"),
        ),
        note="Large catalogue libre. Clé sur build.nvidia.com (vérification téléphone).",
    ),
    Provider(
        id="mistral",
        name="Mistral AI",
        base_url="https://api.mistral.ai/v1",
        env_key="MISTRAL_API_KEY",
        needs_user_key=True,
        logo="🌬️",
        models=(
            ("mistral-small-latest", "Mistral Small"),
            ("ministral-8b-latest", "Ministral 8B"),
            ("open-mistral-nemo", "Mistral Nemo"),
        ),
        note="Clé gratuite sur console.mistral.ai (plan Experiment).",
    ),
    Provider(
        id="cohere",
        name="Cohere",
        base_url="https://api.cohere.com/v2",
        env_key="COHERE_API_KEY",
        needs_user_key=True,
        logo="🧠",
        models=(
            ("command-r-plus", "Command R+"),
            ("command-r", "Command R"),
        ),
        note="Clé gratuite sur dashboard.cohere.com (trail). API légèrement différente (v2).",
    ),
    Provider(
        id="huggingface",
        name="Hugging Face",
        base_url="https://router.huggingface.co/v1",
        env_key="HF_API_KEY",
        needs_user_key=True,
        logo="🤗",
        models=(
            ("microsoft/Phi-3.5-mini-instruct", "Phi-3.5 mini"),
            ("HuggingFaceH4/zephyr-7b-beta", "Zephyr 7B"),
            ("meta-llama/Meta-Llama-3.1-8B-Instruct", "Llama 3.1 8B"),
        ),
        note="Routeur officiel. Token gratuit sur huggingface.co (read + accès aux modèles).",
    ),
)


def all_providers() -> list:
    return list(NO_KEY_PROVIDERS) + list(USER_KEY_PROVIDERS)


def get_provider(provider_id: str) -> Optional[Provider]:
    for p in all_providers():
        if p.id == provider_id:
            return p
    return None
