"""
candy.modules.base — Classe de base v4
"""

from typing import Optional, Generator
from ..client import _client
from ..config import get_profile, Profile


class BoundModule:
    """Module lié à un profil via .use('nom')."""

    def __init__(self, personality: str, profile: Profile):
        self._personality = personality
        self._profile = profile

    # ── Réponse simple ───────────────────────────────────────────────────────

    def ask(self, prompt: str, context: Optional[str] = None) -> str:
        """Envoie un prompt, retourne la réponse."""
        result = _client.ask(self._personality, prompt, self._profile,
                             context=context, stream=False)
        return result.get("response", "")

    # ── Streaming ────────────────────────────────────────────────────────────

    def stream(self, prompt: str, context: Optional[str] = None) -> Generator[str, None, None]:
        """Streame la réponse token par token."""
        yield from _client.ask(self._personality, prompt, self._profile,
                                context=context, stream=True)

    def stream_print(self, prompt: str, context: Optional[str] = None,
                     end: str = "\n", flush: bool = True) -> str:
        """
        Streame ET affiche directement dans le terminal.
        Retourne la réponse complète.
        """
        import sys
        full = []
        for token in self.stream(prompt, context=context):
            sys.stdout.write(token)
            if flush:
                sys.stdout.flush()
            full.append(token)
        sys.stdout.write(end)
        return "".join(full)

    # ── Métadonnées ──────────────────────────────────────────────────────────

    def ask_with_meta(self, prompt: str, context: Optional[str] = None) -> dict:
        """Retourne la réponse + métadonnées (quota, IP, hostname...)."""
        return _client.ask(self._personality, prompt, self._profile,
                           context=context, stream=False)

    # ── Utilitaires ──────────────────────────────────────────────────────────

    def quota(self) -> dict:
        """Quota journalier restant."""
        return _client.quota(self._profile)

    def ping(self) -> float:
        """Latence de l'API en ms."""
        return _client.ping(self._profile)

    def is_online(self) -> bool:
        """Vérifie si l'API est disponible."""
        return _client.is_online(self._profile)

    def __repr__(self):
        name = object.__getattribute__(self._profile, "_name")
        return f"<candy.{self._personality} using profile='{name}'>"


class BaseModule:
    """Classe de base pour toutes les personnalités candy."""

    _personality: str = "full"

    # ── Sélection de profil ──────────────────────────────────────────────────

    @classmethod
    def use(cls, profile_name: str) -> BoundModule:
        """
        Utilise un profil spécifique.

            from candy import cfg, Coding
            cfg.A.lang  = "FR"
            cfg.A.style = "detailed"
            Coding.use("A").ask("Explique les décorateurs")
        """
        return BoundModule(cls._personality, get_profile(profile_name))

    # ── Appels directs (profil default) ─────────────────────────────────────

    @classmethod
    def ask(cls, prompt: str, context: Optional[str] = None) -> str:
        """Appel simple avec le profil 'default'."""
        result = _client.ask(cls._personality, prompt, get_profile("default"),
                             context=context, stream=False)
        return result.get("response", "")

    @classmethod
    def stream(cls, prompt: str, context: Optional[str] = None) -> Generator[str, None, None]:
        """Streaming avec le profil 'default'."""
        yield from _client.ask(cls._personality, prompt, get_profile("default"),
                                context=context, stream=True)

    @classmethod
    def stream_print(cls, prompt: str, context: Optional[str] = None,
                     end: str = "\n") -> str:
        """
        Streame ET affiche dans le terminal.
        Retourne la réponse complète.
        """
        import sys
        full = []
        for token in cls.stream(prompt, context=context):
            sys.stdout.write(token)
            sys.stdout.flush()
            full.append(token)
        sys.stdout.write(end)
        return "".join(full)

    @classmethod
    def ask_with_meta(cls, prompt: str, context: Optional[str] = None) -> dict:
        """Réponse + métadonnées complètes."""
        return _client.ask(cls._personality, prompt, get_profile("default"),
                           context=context, stream=False)

    # ── Utilitaires ──────────────────────────────────────────────────────────

    @classmethod
    def quota(cls) -> dict:
        """Quota journalier restant."""
        return _client.quota(get_profile("default"))

    @classmethod
    def ping(cls) -> float:
        """Latence de l'API en ms."""
        return _client.ping(get_profile("default"))

    @classmethod
    def is_online(cls) -> bool:
        """Vérifie si l'API est disponible."""
        return _client.is_online(get_profile("default"))

    @classmethod
    def personalities(cls) -> list:
        """Liste toutes les personnalités disponibles."""
        return _client.personalities(get_profile("default"))
