"""
candy.conversation — Gestionnaire de conversations multi-tours (v20)
=====================================================================

Nouveautés v20 :
  - Résumé automatique quand l'historique est trop long (auto_compress)
  - Export en Markdown (export_md)
  - Titre automatique de la conversation (title)
  - save(append=True) pour fusionner avec un fichier existant

Usage :
    from candy import Conversation, Coding, cfg

    cfg.A.lang = "FR"

    chat = Conversation(Coding, profile="A")
    print(chat.say("Explique les décorateurs Python"))
    print(chat.say("Donne-moi un exemple avec une classe"))
    print(chat.say("Et avec des arguments ?"))

    print(chat.title)           # titre auto-généré
    chat.show_history()
    chat.export_md("chat.md")   # export Markdown
    chat.save("chat.json")
    chat.save("chat.json", append=True)
    chat.load("chat.json")
    chat.clear()
"""

import json
import os
from typing import Optional
from .client import _client
from .config import get_profile


class Conversation:
    """
    Gestionnaire de conversation multi-tours avec une personnalité candy.
    Mémorise l'historique et l'envoie à chaque requête pour garder le contexte.
    """

    def __init__(self, module, profile: str = "default", max_history: int = 20,
                 auto_compress: bool = True):
        """
        Args:
            module:        Personnalité candy (ex: Coding, Math, Full...)
            profile:       Nom du profil à utiliser (défaut: "default")
            max_history:   Nombre max d'échanges mémorisés (défaut: 20)
            auto_compress: Compresse automatiquement l'historique si trop long (défaut: True)
        """
        self._personality    = module._personality
        self._profile_name   = profile
        self._max_history    = max_history
        self._auto_compress  = auto_compress
        self._history: list  = []
        self._title: Optional[str] = None

    # ── Titre automatique ─────────────────────────────────────────────────────

    @property
    def title(self) -> str:
        """Retourne le titre auto-généré de la conversation (généré au 1er appel)."""
        if self._title is None and self._history:
            self._generate_title()
        return self._title or "Conversation sans titre"

    def _generate_title(self):
        """Génère un titre court à partir du premier échange."""
        if not self._history:
            return
        first_user = next((m["content"] for m in self._history if m["role"] == "user"), "")
        if not first_user:
            return
        try:
            profile = get_profile(self._profile_name)
            result  = _client.ask(
                "summarizer",
                f"Génère un titre court (5 mots max) pour cette conversation. "
                f"Premier message : '{first_user[:200]}'. "
                f"Réponds UNIQUEMENT avec le titre, sans guillemets.",
                profile
            )
            self._title = result.get("response", "").strip().strip('"').strip("'")
        except Exception:
            self._title = first_user[:50] + ("..." if len(first_user) > 50 else "")

    # ── Compression automatique ───────────────────────────────────────────────

    def _compress_history(self):
        """
        Résume les vieux messages pour économiser de l'espace.
        Garde les 4 derniers échanges intacts, résume le reste.
        """
        if len(self._history) <= 8:
            return
        old_part   = self._history[:-8]
        recent_part = self._history[-8:]
        try:
            profile  = get_profile(self._profile_name)
            old_text = "\n".join(
                f"{m['role'].upper()}: {m['content'][:300]}"
                for m in old_part
            )
            result = _client.ask(
                "summarizer",
                f"Résume ce début de conversation en 3-5 phrases clés. "
                f"Préserve les informations techniques importantes.\n\n{old_text}",
                profile
            )
            summary = result.get("response", "")
            compressed = [
                {"role": "assistant", "content": f"[Résumé de la conversation précédente: {summary}]"}
            ]
            self._history = compressed + recent_part
            print("\033[90m[candy] 🗜 Historique compressé automatiquement.\033[0m")
        except Exception:
            # En cas d'échec, tronque simplement
            self._history = self._history[-(self._max_history * 2):]

    # ── Conversation ──────────────────────────────────────────────────────────

    def say(self, prompt: str, context: Optional[str] = None) -> str:
        """
        Envoie un message et retourne la réponse.
        L'historique est automatiquement maintenu.
        """
        profile = get_profile(self._profile_name)
        result  = _client.ask(
            self._personality, prompt, profile,
            context=context, stream=False,
            history=self._history if self._history else None
        )
        response = result.get("response", "")

        self._history.append({"role": "user",      "content": prompt})
        self._history.append({"role": "assistant",  "content": response})

        # Compression automatique ou troncature simple
        if len(self._history) > self._max_history * 2:
            if self._auto_compress:
                self._compress_history()
            else:
                self._history = self._history[-(self._max_history * 2):]

        return response

    def stream_say(self, prompt: str, context: Optional[str] = None):
        """Envoie un message et streame la réponse token par token."""
        import sys
        profile = get_profile(self._profile_name)
        tokens  = []
        gen     = _client.ask(
            self._personality, prompt, profile,
            context=context, stream=True,
            history=self._history if self._history else None
        )
        for token in gen:
            sys.stdout.write(token)
            sys.stdout.flush()
            tokens.append(token)
        sys.stdout.write("\n")
        response = "".join(tokens)
        self._history.append({"role": "user",     "content": prompt})
        self._history.append({"role": "assistant", "content": response})
        return response

    # ── Historique ────────────────────────────────────────────────────────────

    def clear(self):
        """Efface l'historique de conversation."""
        self._history = []
        self._title   = None

    def show_history(self):
        """Affiche l'historique dans le terminal."""
        if not self._history:
            print("\033[90m[candy] Historique vide.\033[0m")
            return
        print(f"\033[95m🍬 Historique — {self._personality} [{self._profile_name}] — {self.title}\033[0m")
        for msg in self._history:
            role  = msg["role"]
            color = "\033[97m" if role == "user" else "\033[96m"
            label = "Vous     " if role == "user" else "candy    "
            print(f"{color}{label}\033[0m {msg['content'][:120]}{'...' if len(msg['content']) > 120 else ''}")

    def get_history(self) -> list:
        """Retourne l'historique brut."""
        return list(self._history)

    def count_turns(self) -> int:
        """Retourne le nombre de tours de conversation."""
        return len(self._history) // 2

    # ── Export ────────────────────────────────────────────────────────────────

    def export_md(self, path: str):
        """
        Exporte la conversation en Markdown.

            chat.export_md("conversation.md")
        """
        lines = [
            f"# {self.title}",
            f"",
            f"> **Personnalité :** {self._personality} | **Profil :** {self._profile_name} | **Tours :** {self.count_turns()}",
            f"",
            "---",
            "",
        ]
        for msg in self._history:
            role  = msg["role"]
            label = "**Vous**" if role == "user" else f"**🍬 candy** _{self._personality}_"
            lines.append(f"### {label}")
            lines.append("")
            lines.append(msg["content"])
            lines.append("")
            lines.append("---")
            lines.append("")

        with open(path, "w", encoding="utf-8") as f:
            f.write("\n".join(lines))
        print(f"\033[90m[candy] Conversation exportée en Markdown → {path}\033[0m")

    # ── Sauvegarde / chargement ───────────────────────────────────────────────

    def save(self, path: str, append: bool = False):
        """
        Sauvegarde l'historique dans un fichier JSON.

        Args:
            path:   Chemin du fichier JSON.
            append: Si True, fusionne avec l'historique existant (défaut: False).
        """
        data = {
            "personality": self._personality,
            "profile":     self._profile_name,
            "title":       self._title,
            "history":     self._history,
        }
        if append and os.path.exists(path):
            try:
                with open(path, "r", encoding="utf-8") as f:
                    old_data = json.load(f)
                data["history"] = old_data.get("history", []) + self._history
            except (json.JSONDecodeError, FileNotFoundError):
                pass
        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        print(f"\033[90m[candy] Historique sauvegardé → {path}\033[0m")

    def load(self, path: str):
        """Charge un historique depuis un fichier JSON."""
        with open(path, "r", encoding="utf-8") as f:
            data = json.load(f)
        self._history = data.get("history", [])
        self._title   = data.get("title")
        print(f"\033[90m[candy] Historique chargé ← {path} ({self.count_turns()} tours)\033[0m")

    def __repr__(self):
        return (f"<Conversation personality={self._personality!r} "
                f"profile={self._profile_name!r} turns={self.count_turns()}>")
