# ============================================================
#  agent.py — Boucle principale et routing — v2.0
#  rolax1212 v2.0 by Roland
# ============================================================

import sys
import subprocess
from pathlib import Path
from .ui          import console, ok, info, warn, err, separateur, confirmer
from .ui          import afficher_aide, banniere_session, afficher_audit
from .llm         import demander_conversation
from .projet      import lire_projet, afficher_structure, lire_task, executer
from .audit       import generer_rapport, corriger_bugs
from .task_parser import generer_task_md, afficher_et_valider, lire_description_fichier
from .generateur  import traiter, executer_tasks
from .frameworks  import detecter_framework, confirmer_framework, init_framework, choisir_framework, FRAMEWORKS
from .logger      import verifier_reprise
from .git_manager import commit_auto, init_git, afficher_statut, historique_git, push, est_repo_git


def lancer(modele, path_str):
    """Point d'entrée principal de l'agent."""

    info(f"Chargement du projet : {path_str}")
    path, fichiers = lire_projet(path_str)
    if path is None:
        sys.exit(1)

    ok(f"{len(fichiers)} fichier(s) chargé(s)")
    afficher_structure(path, fichiers)

    # ── Détection framework ──
    framework = None
    if fichiers:
        detecte = detecter_framework(path, fichiers)
        if detecte:
            # Framework détecté — demande confirmation
            framework = confirmer_framework(detecte)
        else:
            # Aucun framework détecté — demande si le projet en utilise un
            console.print()
            if confirmer("Ce projet utilise-t-il un framework ?", defaut=False):
                framework = choisir_framework()
            else:
                ok("Mode langage libre activé")
                framework = "aucun"

    historique = []

    # ── Vérification reprise session ──
    logger, reprise = verifier_reprise(path)

    # ── Audit automatique si projet existant ──
    fichiers_code = {k: v for k, v in fichiers.items()
                     if not k.endswith(".md") and not k.endswith(".txt")}

    if fichiers_code and not reprise:
        info("Projet existant détecté — audit automatique...")
        _faire_audit(path, fichiers, modele, historique)

    # ── Reprise session interrompue ──
    if reprise:
        task_path, task_contenu = lire_task(path)
        if task_contenu:
            from .projet import extraire_taches
            taches = extraire_taches(task_contenu)
            restantes = logger.taches_restantes(taches)
            if restantes:
                info(f"{len(restantes)} tâche(s) restante(s)")
                executer_tasks(task_path, task_contenu, path, modele,
                               fichiers, historique, logger=logger,
                               taches_filtrees=restantes)
    else:
        # ── Task.md détecté ──
        task_path, task_contenu = lire_task(path)
        if task_contenu:
            console.print(f"\n[bold yellow]Task.md détecté ![/bold yellow]")
            if confirmer("Exécuter les tâches du Task.md maintenant ?", defaut=False):
                executer_tasks(task_path, task_contenu, path, modele,
                               fichiers, historique, logger=logger)

    # ── Bannière + boucle ──
    banniere_session(modele, path)
    logger.afficher_resume()

    while True:
        try:
            separateur()
            commande = console.input("\n[bold green]Toi >[/bold green] ").strip()
            if not commande:
                continue
            _router(commande, path, modele, fichiers, historique, framework, logger)
        except KeyboardInterrupt:
            console.print("\n\n[bold cyan]Ctrl+C — tape 'exit' pour quitter.[/bold cyan]")
        except EOFError:
            break


# ============================================================
#  ROUTING
# ============================================================
def _router(commande, path, modele, fichiers, historique, framework, logger):
    cmd = commande.lower().strip()

    if cmd in ["exit", "quit", "bye", "/bye", "quitte", "au revoir"]:
        logger.session_fin()
        console.print("\n[bold cyan]rolax1212 — À bientôt ![/bold cyan]\n")
        sys.exit(0)

    if cmd in ["aide", "help", "/help"]:
        afficher_aide()
        return

    if cmd in ["structure", "arbre", "tree", "fichiers", "ls"]:
        afficher_structure(path, fichiers)
        return

    if cmd in ["audit", "analyse", "check", "cuf", "rapport"]:
        _faire_audit(path, fichiers, modele, historique)
        return

    if cmd in ["task", "tasks", "todo", "taches", "tâches"]:
        task_path, task_contenu = lire_task(path)
        if task_contenu:
            executer_tasks(task_path, task_contenu, path, modele,
                           fichiers, historique, logger=logger)
        else:
            warn("Aucun Task.md trouvé. Utilise 'plan' pour en créer un.")
        return

    # ── Init framework ──
    if cmd.startswith("init"):
        reste = commande[4:].strip().lower()
        cle   = reste if reste in FRAMEWORKS else None
        if not cle:
            cle = choisir_framework()
        init_framework(cle, path)
        # Recharge le projet après init
        from .projet import lire_projet as _lire
        _, nouveaux = _lire(str(path))
        fichiers.update(nouveaux)
        return

    # ── Changer de framework ──
    if cmd in ["framework", "fw", "changer framework"]:
        nouveau = choisir_framework()
        ok(f"Framework changé : {nouveau}")
        framework = nouveau
        return

    if cmd.startswith("plan"):
        description = commande[4:].strip()
        if description.endswith(".txt") and (Path(description).exists() or (Path(path) / description).exists()):
            chemin_txt = Path(description) if Path(description).exists() else Path(path) / description
            description = lire_description_fichier(chemin_txt) or description

        if not description:
            console.print("[dim]Décris ton projet en français (langage libre).[/dim]")
            console.print("[dim]Termine avec une ligne vide.[/dim]\n")
            lignes = []
            while True:
                ligne = console.input("  ").strip()
                if not ligne:
                    break
                lignes.append(ligne)
            description = "\n".join(lignes)

        if not description:
            warn("Aucune description fournie.")
            return

        contenu = generer_task_md(description, modele, fichiers, path)
        if contenu and afficher_et_valider(contenu, path):
            task_path, task_contenu = lire_task(path)
            if task_contenu and confirmer("Exécuter les tâches maintenant ?", defaut=False):
                executer_tasks(task_path, task_contenu, path, modele,
                               fichiers, historique, logger=logger)
        return

    if cmd.startswith("lis ") or cmd.startswith("affiche "):
        nom    = commande.split(" ", 1)[1].strip()
        chemin = Path(path) / nom
        if chemin.exists():
            from .ui import code as afficher_code
            from .projet import EXTENSIONS_CODE
            lang = EXTENSIONS_CODE.get(chemin.suffix, "text")
            afficher_code(chemin.read_text(encoding="utf-8"), lang)
        else:
            err(f"Fichier '{nom}' introuvable.")
        return

    if cmd.startswith("exec ") or cmd.startswith("run "):
        nom    = commande.split(" ", 1)[1].strip()
        chemin = Path(path) / nom
        if not chemin.exists():
            err(f"Fichier '{nom}' introuvable.")
            return

        # Confirmation avant exécution
        if not confirmer(f"Êtes‑vous sûr de vouloir exécuter '{nom}' ? Cette action peut être dangereuse.", defaut=False):
            warn("Exécution annulée.")
            return

        # Exécution sandboxée (limitation simple)
        try:
            # Déterminer la commande selon l'extension
            if chemin.suffix == ".py":
                cmd_list = [sys.executable, str(chemin)]
            elif chemin.suffix == ".js":
                cmd_list = ["node", str(chemin)]
            elif chemin.suffix in {".sh", ".bash"}:
                cmd_list = ["bash", str(chemin)]
            else:
                # Pour les exécutables natifs
                cmd_list = [str(chemin)]

            result = subprocess.run(
                cmd_list,
                cwd=path,
                capture_output=True,
                text=True,
                timeout=30,
                env={"PATH": ""}  # environnement très limité
            )
        except subprocess.TimeoutExpired:
            err("Exécution interrompue : dépassement du temps imparti.")
            return
        except Exception as e:
            err(f"Erreur lors de l'exécution : {e}")
            return

        if result.stdout:
            console.print(f"\n[dim]Sortie :[/dim]\n{result.stdout}")
        if result.stderr:
            console.print(f"\n[red]Erreur :[/red]\n{result.stderr}")
        return

    # ── Git ──
    if cmd in ["git", "commit", "git commit"]:
        commit_auto(path, modele, fichiers, historique)
        return

    if cmd in ["git init"]:
        init_git(path)
        return

    if cmd in ["git status", "git st"]:
        afficher_statut(path)
        return

    if cmd in ["git log", "git historique"]:
        historique_git(path)
        return

    if cmd in ["git push"]:
        push(path)
        return

    if cmd.startswith("git commit -m ") or cmd.startswith("commit "):
        message = commande.split(" ", 2)[-1].strip().strip('"').strip("'")
        from .git_manager import commit_message_libre
        commit_message_libre(path, message)
        return

    traiter(commande, path, modele, fichiers, historique, framework=framework)


# ============================================================
#  AUDIT
# ============================================================
def _faire_audit(path, fichiers, modele, historique):
    rapport = generer_rapport(fichiers, modele)
    bugs    = rapport.get("check", [])
    if bugs:
        info(f"{len(bugs)} bug(s) détecté(s) — correction automatique...")
        rapport = corriger_bugs(rapport, path, fichiers, modele)
    afficher_audit(rapport)
    historique.append({
        "role": "assistant",
        "content": f"Audit terminé. Bugs: {len(bugs)}. "
                   f"Updates: {len(rapport.get('update', []))}. "
                   f"Future: {len(rapport.get('future', []))}."
    })