"""
main.py — Point d'entrée CLI de l'agent immobilier.

Démarrage :
    python main.py

L'agent écoute en boucle :
  1. Un fichier .m4a déposé dans le dossier → transcription Whisper + suppression.
  2. Une saisie texte clavier.
  3. 'quitter' → arrêt.
"""

from dotenv import load_dotenv
load_dotenv()

import logging
import threading

from domain.audio import trouver_enregistrement, transcrire_fichier
import domain.agent.memory as memory
import domain.core.langfuse_http as langfuse_http
import domain.core.scorer as scorer
from domain.agent.react import react_loop, _afficher_resultat, HORS_SCOPE
from domain.core.llm import appeler_llm, classifier_question, get_client
from domain.core.security import valider_input, InputSecurityError
from domain.tools.database import setup_db

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s — %(message)s",
    datefmt="%H:%M:%S",
)
logger = logging.getLogger("agent")


# ── Préchauffage connexion OpenAI ─────────────────────────────────────────────

def _prechauffer() -> None:
    """
    Établit la connexion HTTP vers l'API OpenAI au démarrage.
    Appelé dans un thread daemon en parallèle de setup_db().
    """
    try:
        get_client().models.list()
        logger.info("Préchauffage connexion OpenAI terminé.")
    except Exception as e:
        logger.warning(f"Préchauffage connexion OpenAI échoué (non bloquant) : {e}")


# ── Lecture de la question ────────────────────────────────────────────────────

def _lire_question() -> str | None:
    """
    Lit la prochaine question.

    Priorité :
      1. Fichier .m4a présent dans le dossier du projet → transcription Whisper + suppression.
      2. Saisie texte clavier.
      3. 'quitter' → None (signal d'arrêt).
    """
    chemin = trouver_enregistrement()
    if chemin:
        return transcrire_fichier(chemin)

    try:
        saisie = input("Vous : ").strip()
    except (EOFError, KeyboardInterrupt):
        return None

    if saisie.lower() in ("quitter", "exit", "quit"):
        return None

    return saisie


# ── Boucle principale ─────────────────────────────────────────────────────────

def main():
    warmup = threading.Thread(target=_prechauffer, daemon=True, name="warmup-openai")
    warmup.start()

    setup_db()
    memory.clear()
    logger.info("Base de données et mémoire initialisées.")

    warmup.join(timeout=10)

    print("Agent immobilier — déposez un fichier .m4a dans le dossier du projet ou tapez votre question.")
    print("Tapez 'quitter' pour terminer.\n")

    while True:
        question = _lire_question()

        if question is None:
            print("\nAu revoir !")
            break
        if not question:
            continue

        try:
            valider_input(question)
        except InputSecurityError as e:
            logger.warning(f"[SECURITY] Entrée rejetée : {e}")
            print(f"\nAgent : {e}\n")
            continue

        try:
            logger.info(f"Question reçue : {question!r}")
            logger.info(f"Mémoire : {len(memory.recall(memory.MAX_MESSAGES))} message(s) en contexte.")

            trace_id = langfuse_http.create_trace(name="agent-question", input=question)
            mode     = classifier_question(question, memory.recall(4))
            logger.info(f"Mode détecté : {mode}")

            if mode == "hors_scope":
                logger.info("Hors scope — réponse fixe, mémoire non mise à jour.")
                langfuse_http.update_trace(trace_id, output=HORS_SCOPE, metadata={"mode": "hors_scope"})
                print(f"\nAgent : {HORS_SCOPE}\n")
                continue

            elif mode == "conversation":
                logger.info("Mode conversation — réponse texte libre.")
                reponse_str = appeler_llm(question, historique=memory.recall(3))
                langfuse_http.update_trace(trace_id, output=reponse_str, metadata={"mode": "conversation"})
                print(f"\nAgent : {reponse_str}\n")

            else:
                logger.info("Mode analyse — lancement de la boucle ReAct.")
                resultat    = react_loop(question, memory.recall(3))
                reponse_str = _afficher_resultat(resultat)
                langfuse_http.update_trace(trace_id, output=reponse_str, metadata={"mode": "analyse"})
                print(f"\nAgent :\n{reponse_str}\n")

            scorer.noter_async(trace_id, question, reponse_str)
            memory.store({"role": "user",      "content": question})
            memory.store({"role": "assistant",  "content": reponse_str})
            logger.info(f"Mémoire mise à jour : {len(memory.recall(memory.MAX_MESSAGES))} message(s) stockés.")

        except (ValueError, RuntimeError) as e:
            logger.error(f"Erreur : {e}")
            print(f"Erreur : {e}\n")


if __name__ == "__main__":
    main()
