"""Abstraction des moteurs LLM (backend pluggable).

Calque du pattern TTS (`tts/base.py`) : un backend ne fait *qu'une* chose,
transformer une liste de messages (role/content) en texte brut. Toute la logique
agnostique (calcul des parametres depuis les Settings, retrait de la pensee,
extraction JSON tolerante, retries) vit dans la facade `client.LLM`, jamais
dupliquee par backend.
"""
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Callable, Optional


class LLMBackend(ABC):
    """Interface commune a tous les moteurs LLM."""

    name: str = "base"

    def __init__(self, model_ref: str):
        # Reference du modele, interpretee par le backend : id mlx-community
        # (mlx) ou nom du modele charge dans LM Studio (lmstudio, vide -> actif).
        self.model_ref = model_ref

    @abstractmethod
    def complete(
        self,
        messages: list[dict],
        *,
        max_tokens: int,
        temperature: float,
        reasoning: bool,
        token_sink: Optional[Callable[[str], None]] = None,
    ) -> str:
        """Genere et renvoie le texte BRUT (chaine de pensee incluse).

        - `messages` : liste {role, content} (system optionnel + user).
        - `reasoning` : si vrai, le modele peut emettre une chaine de pensee ;
          le backend peut s'arreter des que le JSON post-pensee est complet. La
          facade retire la pensee en aval (`_strip_reasoning`).
        - `token_sink` : si fourni, appele avec chaque morceau de texte au fil de
          la generation (streaming pour `inkflow benchmark --stream`).
        """
