"""
candy.logger — Logs structurés JSON (v21)
==========================================

Loggue chaque appel API dans un fichier JSON structuré.
Utile pour débugger en production, auditer les coûts, analyser les usages.

Usage :
    from candy import CandyLogger, Coding

    # Activer les logs
    CandyLogger.enable("candy_logs.jsonl")    # fichier JSONL (une ligne = un appel)
    CandyLogger.enable()                      # défaut : ~/.candy/logs/candy.jsonl

    response = Coding.ask("Write a sort")
    # → loggue automatiquement : timestamp, personality, prompt, response, latency_ms

    # Lire les logs
    logs = CandyLogger.read(last_n=10)
    for entry in logs:
        print(entry["personality"], entry["latency_ms"], "ms")

    # Stats rapides
    print(CandyLogger.stats())
    # → {"total_calls": 42, "avg_latency_ms": 312, "top_personality": "coding", ...}

    # Désactiver
    CandyLogger.disable()

    # Vider les logs
    CandyLogger.clear()
"""

import json
import time
from pathlib import Path
from typing import Optional
from datetime import datetime

_DEFAULT_LOG = Path.home() / ".candy" / "logs" / "candy.jsonl"
_log_path: Optional[Path] = None
_enabled: bool = False


class _CandyLogger:

    def enable(self, path: Optional[str] = None):
        """
        Active les logs structurés.

            CandyLogger.enable()                   # ~/.candy/logs/candy.jsonl
            CandyLogger.enable("mes_logs.jsonl")   # fichier custom
        """
        global _log_path, _enabled
        _log_path = Path(path) if path else _DEFAULT_LOG
        _log_path.parent.mkdir(parents=True, exist_ok=True)
        _enabled = True
        print(f"\033[90m[candy] 📋 Logs activés → {_log_path}\033[0m")

    def disable(self):
        """Désactive les logs sans effacer le fichier."""
        global _enabled
        _enabled = False
        print("\033[90m[candy] 📋 Logs désactivés.\033[0m")

    def is_enabled(self) -> bool:
        return _enabled

    def log(self, entry: dict):
        """
        Loggue une entrée. Appelé automatiquement par le client v21.
        Peut aussi être appelé manuellement.
        """
        if not _enabled or not _log_path:
            return
        try:
            entry.setdefault("timestamp", datetime.utcnow().isoformat() + "Z")
            with open(_log_path, "a", encoding="utf-8") as f:
                f.write(json.dumps(entry, ensure_ascii=False) + "\n")
        except Exception:
            pass

    def read(self, last_n: int = 50, personality: Optional[str] = None) -> list:
        """
        Lit les N dernières entrées de log.

            logs = CandyLogger.read(last_n=20)
            logs = CandyLogger.read(last_n=50, personality="coding")
        """
        path = _log_path or _DEFAULT_LOG
        if not path.exists():
            return []
        entries = []
        try:
            lines = path.read_text(encoding="utf-8").strip().splitlines()
            for line in lines:
                try:
                    entry = json.loads(line)
                    if personality and entry.get("personality") != personality:
                        continue
                    entries.append(entry)
                except json.JSONDecodeError:
                    pass
        except Exception:
            pass
        return entries[-last_n:]

    def stats(self, last_n: int = 1000) -> dict:
        """
        Statistiques sur les derniers appels.

            print(CandyLogger.stats())
            # → {"total_calls": 42, "avg_latency_ms": 312, "top_personality": "coding", ...}
        """
        entries = self.read(last_n=last_n)
        if not entries:
            return {"total_calls": 0, "message": "Aucun log disponible."}

        latencies     = [e.get("latency_ms", 0) for e in entries if e.get("latency_ms")]
        personalities = [e.get("personality", "?") for e in entries]
        errors        = [e for e in entries if e.get("error")]

        from collections import Counter
        top = Counter(personalities).most_common(1)

        return {
            "total_calls":      len(entries),
            "error_count":      len(errors),
            "avg_latency_ms":   round(sum(latencies) / len(latencies), 1) if latencies else 0,
            "min_latency_ms":   min(latencies) if latencies else 0,
            "max_latency_ms":   max(latencies) if latencies else 0,
            "top_personality":  top[0][0] if top else "?",
            "top_count":        top[0][1] if top else 0,
            "personalities":    dict(Counter(personalities)),
            "log_file":         str(_log_path or _DEFAULT_LOG),
        }

    def clear(self):
        """Vide le fichier de logs."""
        path = _log_path or _DEFAULT_LOG
        if path.exists():
            path.write_text("", encoding="utf-8")
        print(f"\033[90m[candy] 📋 Logs effacés → {path}\033[0m")

    def tail(self, n: int = 10):
        """Affiche les N dernières entrées dans le terminal."""
        entries = self.read(last_n=n)
        if not entries:
            print("\033[90m[candy] Aucun log disponible.\033[0m")
            return
        cyan  = "\033[96m"
        gray  = "\033[90m"
        green = "\033[92m"
        reset = "\033[0m"
        print(f"\n{cyan}📋 candy logs — {len(entries)} dernières entrées{reset}\n")
        for e in entries:
            ts   = e.get("timestamp", "")[:19].replace("T", " ")
            pers = e.get("personality", "?")
            ms   = e.get("latency_ms", "?")
            err  = e.get("error", "")
            col  = "\033[91m" if err else green
            print(f"  {gray}{ts}{reset}  {cyan}{pers:<16}{reset}  {col}{ms} ms{reset}  {gray}{e.get('prompt','')[:60]}{reset}")
        print()


CandyLogger = _CandyLogger()
