#!/usr/bin/env python3
###############################################################################
##
## MODULE      : tm_gemini.py
## DESCRIPTION : Gemini Session for TeXmacs via tmpy avec historique
## COPYRIGHT   : (C) 2025 TeXmacs Community
##
## This software falls under the GNU general public license version 3 or later.
## It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
## in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
###############################################################################

import os
import sys
import platform
import traceback
import re
from os.path import exists

# ---------------------------------------------------------------------------
# Standard tmpy setup
# ---------------------------------------------------------------------------
tmpy_home_path = os.environ.get("TEXMACS_HOME_PATH") + "/plugins/tmpy"
if (exists(tmpy_home_path)):
    sys.path.append(os.environ.get("TEXMACS_HOME_PATH") + "/plugins/")
else:
    sys.path.append(os.environ.get("TEXMACS_PATH") + "/plugins/")

# tmpy imports
from tmpy.protocol import *
from tmpy.compat import *

# ---------------------------------------------------------------------------
# Gemini imports & configuration
# ---------------------------------------------------------------------------
import google.generativeai as genai

GEMINI_API_KEY = "YOU CLE API"   # <<< Mets ta clé ici
genai.configure(api_key=GEMINI_API_KEY)

# Historique de conversation
conversation_history = []

def ask_gemini(prompt: str, history: list) -> str:
    """Envoie une question à Gemini avec l'historique de conversation"""
    try:
        # Construire le prompt avec l'historique
        context = "Contexte de la conversation précédente:\n\n"
        for i, (user_msg, assistant_msg) in enumerate(history):
            context += f"Question {i+1}: {user_msg}\n"
            context += f"Réponse {i+1}: {assistant_msg}\n\n"
        
        full_prompt = f"{context}Nouvelle question: {prompt}\n\nRéponse:"
        
        model = genai.GenerativeModel(
            "YOU MODEL",
            system_instruction=(
                "Tu es un assistant LaTeX expert en mathématiques. "
                "Réponds en tenant compte de l'historique de conversation fourni. "
                "Utilise du LaTeX valide avec $$...$$ pour les formules display et $...$ pour les formules en ligne. "
                "Sois concis et précis dans tes réponses."
            )
        )
        
        response = model.generate_content(full_prompt)
        if response.text:
            return response.text.strip()
        else:
            return "❌ Erreur : réponse vide de Gemini."
    except Exception as e:
        return f"❌ Erreur Gemini : {e}"

import re

# regex pour repérer les blocs math (display) : $$...$$ | \[...\] | \begin{ENV}...\end{ENV}
BLOCK_RE = re.compile(r'(\$\$.*?\$\$|\\\[.*?\\\]|\\begin\{([a-zA-Z*]+)\}.*?\\end\{\2\})', re.S)

# regex pour repérer les maths inline $...$
INLINE_RE = re.compile(r'(\$(?:\\.|[^$])+\$)', re.S)

def _send_text_piece(txt: str):
    """Envoie du texte brut (pas de maths) : normalise les retours à la ligne en espaces."""
    txt = re.sub(r'\s+', ' ', txt)  # garder une seule espace entre mots
    if txt.strip():
        flush_verbatim(txt)

def _send_inline_math(dollar_expr: str):
    """Envoie une formule inline : dollar_expr inclut les $...$."""
    inner = dollar_expr[1:-1]  # enlève les $ extérieurs
    # Envoie en inline math avec \( ... \)
    flush_latex(r'\(' + inner + r'\)')

def display_response(response: str):
    """
    Envoie:
      - les blocs display (= $$...$$, \[...\], \begin{env}...\end{env}) via flush_latex sur leur propre ligne,
      - les segments entre blocs sont découpés en texte + inline math, et envoyés sans sauts de ligne
        (texte via flush_verbatim, inline via flush_latex(\(...\)) ), puis on termine par un flush_newline().
    """
    pos = 0
    for m in BLOCK_RE.finditer(response):
        pre = response[pos:m.start()]
        if pre and pre.strip():
            # traiter le texte avant le bloc : découpe inline/text
            parts = INLINE_RE.split(pre)
            for part in parts:
                if not part:
                    continue
                if INLINE_RE.fullmatch(part):
                    _send_inline_math(part)
                else:
                    _send_text_piece(part)
            # fin du segment mixte -> terminer ligne
            flush_newline()

        # envoyer le bloc display tel quel (sur sa propre ligne)
        block = m.group(1)
        flush_latex(block.strip())
        flush_newline()

        pos = m.end()

    # reste après dernier bloc
    tail = response[pos:]
    if tail and tail.strip():
        parts = INLINE_RE.split(tail)
        for part in parts:
            if not part:
                continue
            if INLINE_RE.fullmatch(part):
                _send_inline_math(part)
            else:
                _send_text_piece(part)
        flush_newline()

# ---------------------------------------------------------------------------
# Session main loop avec historique
# ---------------------------------------------------------------------------
def main():
    global conversation_history
    
    flush_verbatim("Gemini Session for TeXmacs (avec historique)")
    flush_newline()
    flush_verbatim(f"Python {platform.python_version()} [{sys.executable}]")
    flush_newline(2)

    try:
        while True:
            line = tm_input()
            if not line or not line.strip():
                continue

            try:
                # Obtenir la réponse de Gemini avec historique
                response = ask_gemini(line, conversation_history)
                
                # Ajouter à l'historique
                conversation_history.append((line, response))
                
                # Limiter la taille de l'historique pour éviter les tokens excessifs
                if len(conversation_history) > 10:
                    conversation_history = conversation_history[-10:]
                
                # Afficher la réponse
                display_response(response)
                flush_newline()

            except Exception as e:
                flush_verbatim(f"Erreur : {str(e)}")
                flush_newline()
                flush_verbatim(traceback.format_exc())
                flush_newline(2)

    except (KeyboardInterrupt, EOFError):
        flush_verbatim("Session terminée.")
        flush_newline()

# ---------------------------------------------------------------------------
# Session startup
# ---------------------------------------------------------------------------
if __name__ == "__main__":
    main()
