#!/usr/bin/env python3
"""
hermes-doc-worker — Hermes analyse admin/, écrit ses rapports dans
admin/hermes/builtin/ et push dans sa branche hermes/daily-work.
Ré-ingère tout admin/ dans Qdrant à chaque run.

Modes :
  (défaut)    : analyse un batch de fichiers, écrit rapport, push, ré-ingère
  --daily-pr  : crée une PR hermes/daily-work → main sur GitHub + retourne l'URL
  --dry-run   : analyse sans écrire ni push
"""

import argparse
import json
import os
import subprocess
import sys
from datetime import datetime
from pathlib import Path

REPO_DIR    = Path("/srv/data/lab/Funk-lab")
BRANCH      = "hermes/daily-work"
ADMIN_DIR   = REPO_DIR / "admin"
BUILTIN_DIR = REPO_DIR / "admin" / "hermes" / "builtin"
RAG_DOCS    = Path("/srv/data/rag/docs")
STATE_FILE  = Path("/var/lib/hermes-auto-improve/state.json")
MAX_FILES   = 5   # fichiers analysés par run


# ── Git helpers ──────────────────────────────────────────────────

def git(args: list) -> subprocess.CompletedProcess:
    return subprocess.run(
        ["git", "-C", str(REPO_DIR)] + args,
        capture_output=True, text=True
    )


def git_sync():
    """S'assure qu'on est sur hermes/daily-work à jour."""
    git(["config", "user.email", "hermes@funk.lab"])
    git(["config", "user.name",  "Hermes Bot"])
    git(["fetch", "origin"])
    r = git(["checkout", BRANCH])
    if r.returncode != 0:
        git(["checkout", "-b", BRANCH, f"origin/{BRANCH}"])
    git(["pull", "--rebase", "origin", BRANCH])


# ── Hermes ───────────────────────────────────────────────────────

def ask_hermes(prompt: str) -> str:
    safe = prompt.replace("'", "'\\''")
    cmd  = [
        "sudo", "-i", "-u", "hermes", "bash", "-c",
        f'HERMES_HOME=/srv/data/hermes hermes --profile funk-ai -z \'{safe}\''
    ]
    r = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
    return r.stdout.strip()


# ── Analyse d'un fichier ─────────────────────────────────────────

def analyze_file(fpath: Path) -> dict:
    rel     = str(fpath.relative_to(REPO_DIR))
    content = fpath.read_text(encoding="utf-8", errors="replace")

    prompt = f"""Tu es l'agent de documentation du homelab Funk.
Analyse ce fichier de documentation et produis un rapport structuré.

Fichier : {rel}
---
{content[:4000]}
---

Réponds UNIQUEMENT en JSON valide (aucun texte avant ou après) :
{{
  "fichier": "{rel}",
  "statut": "ok" | "à_jour" | "obsolète" | "incomplet" | "erreur",
  "score_qualité": 1-10,
  "résumé": "une phrase sur l'état de ce document",
  "problèmes": ["liste des problèmes concrets trouvés"],
  "suggestions": ["liste des améliorations prioritaires"],
  "état_réel": "ce que tu sais de l'état actuel de ce composant dans Funk (ou null)"
}}"""

    raw = ask_hermes(prompt)

    try:
        start = raw.find("{")
        end   = raw.rfind("}") + 1
        if start >= 0 and end > start:
            return json.loads(raw[start:end])
    except json.JSONDecodeError:
        pass

    return {
        "fichier":        rel,
        "statut":         "erreur_parse",
        "score_qualité":  0,
        "résumé":         "Hermes n'a pas retourné de JSON valide",
        "problèmes":      [],
        "suggestions":    [],
        "état_réel":      None,
        "_raw":           raw[:300]
    }


# ── Ré-ingestion Qdrant ──────────────────────────────────────────

def rag_ingest() -> str:
    # Sync admin/ du clone vers /srv/data/rag/docs/
    subprocess.run(
        ["rsync", "-a", "--delete",
         str(ADMIN_DIR) + "/",
         str(RAG_DOCS) + "/"],
        check=True
    )
    r = subprocess.run(
        ["/usr/local/bin/rag-ingest"],
        capture_output=True, text=True, timeout=300
    )
    return (r.stdout + r.stderr).strip()[-300:]


# ── Créer la PR GitHub ───────────────────────────────────────────

def _get_open_hermes_pr():
    """Retourne le numéro et l'URL de la PR Hermes ouverte, ou None."""
    r = subprocess.run(
        ["gh", "pr", "list", "--repo", "Alkatrazz24/Funk-lab",
         "--head", BRANCH, "--state", "open", "--json", "number,url"],
        capture_output=True, text=True, timeout=30, cwd=str(REPO_DIR)
    )
    if r.returncode != 0:
        return None
    try:
        prs = json.loads(r.stdout)
        return prs[0] if prs else None
    except (json.JSONDecodeError, IndexError):
        return None


def create_github_pr(summary: str) -> dict:
    today = datetime.now().strftime("%Y-%m-%d")
    diff  = git(["diff", "--stat", "origin/main...HEAD"])
    stats = diff.stdout.strip() or "Aucune modification depuis main"

    title = f"[Hermes] Rapport documentation — {today}"
    body  = f"""## Rapport quotidien Hermes — {today}

Ce Pull Request est créé automatiquement par Hermes à 22h.

### Ce que Hermes a fait aujourd'hui
{summary}

### Diff depuis main
```
{stats[:2000]}
```

### Comment reviewer
1. Vérifier les rapports dans `admin/hermes/builtin/`
2. Merger quand tout semble correct (squash merge configuré)

> Généré par `hermes-doc-worker` · branche `{BRANCH}`
"""

    existing = _get_open_hermes_pr()
    if existing:
        # Met à jour le titre et le corps de la PR existante
        subprocess.run(
            ["gh", "pr", "edit", str(existing["number"]),
             "--repo",  "Alkatrazz24/Funk-lab",
             "--title", title,
             "--body",  body],
            capture_output=True, text=True, timeout=30, cwd=str(REPO_DIR)
        )
        return {"html_url": existing["url"],
                "number":   existing["number"],
                "title":    title,
                "updated":  True}

    r = subprocess.run(
        ["gh", "pr", "create",
         "--title", title,
         "--body",  body,
         "--head",  BRANCH,
         "--base",  "main",
         "--repo",  "Alkatrazz24/Funk-lab"],
        capture_output=True, text=True, timeout=30, cwd=str(REPO_DIR)
    )
    if r.returncode == 0:
        pr_url = r.stdout.strip()
        return {"html_url": pr_url, "title": title}
    return {"error": r.stderr.strip() or "gh pr create a échoué"}


# ── Main ─────────────────────────────────────────────────────────

def load_state() -> dict:
    if STATE_FILE.exists():
        return json.loads(STATE_FILE.read_text())
    return {"processed": [], "runs_today": 0, "last_run": None}


def save_state(state: dict):
    STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
    STATE_FILE.write_text(json.dumps(state, indent=2, ensure_ascii=False))


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--daily-pr", action="store_true", help="Créer PR GitHub + résumé journalier")
    parser.add_argument("--dry-run",  action="store_true", help="Analyser sans écrire ni push")
    parser.add_argument("--all",      action="store_true", help="Analyser tous les fichiers en une passe (ignore MAX_FILES)")
    parser.add_argument("--subdir",   default=None,        help="Sous-dossier admin/ (ex: ia, k8s)")
    args = parser.parse_args()

    now    = datetime.now()
    run_ts = now.strftime("%Y-%m-%d_%H-%M")
    today  = now.strftime("%Y-%m-%d")

    # ── Sync branche ─────────────────────────────────────────────
    if not args.dry_run:
        git_sync()

    state = load_state()

    # ── Mode PR journalier ────────────────────────────────────────
    if args.daily_pr:
        # Résumé des runs du jour
        builtin_today = sorted(BUILTIN_DIR.glob(f"{today}_*.md")) if BUILTIN_DIR.exists() else []
        summary_parts = []
        for rpt in builtin_today[-5:]:
            summary_parts.append(rpt.read_text()[:500])
        daily_summary = "\n\n---\n\n".join(summary_parts) or "Aucun rapport généré aujourd'hui."

        pr = create_github_pr(daily_summary)
        result = {
            "action":     "daily_pr",
            "pr_url":     pr.get("html_url", ""),
            "pr_number":  pr.get("number", 0),
            "pr_title":   pr.get("title", ""),
            "reports_today": len(builtin_today),
            "error":      pr.get("error", "")
        }
        print(json.dumps(result, indent=2, ensure_ascii=False))
        return

    # ── Sélection des fichiers à analyser ─────────────────────────
    scan_root = ADMIN_DIR / args.subdir if args.subdir else ADMIN_DIR
    all_md    = [
        f for f in sorted(scan_root.rglob("*.md"))
        if "hermes/builtin" not in str(f)   # ne pas analyser ses propres rapports
    ]

    if args.all:
        batch = all_md
        state["processed"] = []
    else:
        # Rotation : reprend là où il s'est arrêté
        todo = [f for f in all_md if str(f) not in state["processed"]]
        if not todo:
            state["processed"] = []
            todo = all_md
        batch = todo[:MAX_FILES]
    results = []

    # ── Analyse ───────────────────────────────────────────────────
    for fpath in batch:
        rel = str(fpath.relative_to(REPO_DIR))
        print(f"  → {rel}", flush=True)

        analysis = analyze_file(fpath)
        results.append(analysis)
        state["processed"].append(str(fpath))
        print(f"    {analysis.get('statut','?')} — {analysis.get('score_qualité','?')}/10", flush=True)

    save_state(state)

    if not results:
        print(json.dumps({"error": "aucun fichier à analyser"}))
        return

    # ── Écriture du rapport dans admin/hermes/builtin/ ────────────
    BUILTIN_DIR.mkdir(parents=True, exist_ok=True)
    report_path = BUILTIN_DIR / f"{run_ts}.md"

    lines  = [f"# Rapport Hermes — {run_ts}\n"]
    lines += [f"> Branche : `{BRANCH}` · Fichiers analysés : {len(results)}\n"]
    lines += ["\n---\n"]

    ok_count  = sum(1 for r in results if r.get("statut") in ("ok", "à_jour"))
    bad_count = len(results) - ok_count

    lines += [f"## Résumé\n",
              f"- ✅ À jour : {ok_count}\n",
              f"- ⚠️  À améliorer : {bad_count}\n\n"]

    for r in results:
        icon = "✅" if r.get("statut") in ("ok", "à_jour") else "⚠️"
        lines.append(f"## {icon} `{r['fichier']}` — {r.get('score_qualité', '?')}/10\n\n")
        lines.append(f"**Statut** : {r.get('statut', '?')}  \n")
        lines.append(f"**Résumé** : {r.get('résumé', '')}  \n\n")

        if r.get("problèmes"):
            lines.append("**Problèmes :**\n")
            for p in r["problèmes"]:
                lines.append(f"- {p}\n")
            lines.append("\n")

        if r.get("suggestions"):
            lines.append("**Suggestions :**\n")
            for s in r["suggestions"]:
                lines.append(f"- {s}\n")
            lines.append("\n")

        if r.get("état_réel"):
            lines.append(f"**État réel connu de Hermes :**  \n{r['état_réel']}\n\n")

        lines.append("---\n\n")

    if not args.dry_run:
        report_path.write_text("".join(lines), encoding="utf-8")
        print(f"\n✓ Rapport : {report_path.relative_to(REPO_DIR)}", flush=True)

    # ── Commit + push ─────────────────────────────────────────────
    if not args.dry_run:
        git(["add", str(report_path.relative_to(REPO_DIR))])

        if git(["diff", "--cached", "--quiet"]).returncode != 0:
            git(["commit", "-m",
                 f"docs(hermes): rapport analyse {run_ts} — {len(results)} fichiers\n\n"
                 f"Analysés : {', '.join(r['fichier'].split('/')[-1] for r in results)}\n"
                 f"À améliorer : {bad_count}/{len(results)}\n\n"
                 "Co-Authored-By: Hermes <hermes@funk.lab>"])
            git(["push", "origin", BRANCH])
            print(f"✓ Push → {BRANCH}", flush=True)

        # ── Ré-ingestion Qdrant (toujours) ────────────────────────
        print("\n⏳ Qdrant re-ingest...", flush=True)
        ingest_out = rag_ingest()
        print(f"  {ingest_out}", flush=True)

    # ── Résumé JSON pour n8n ─────────────────────────────────────
    summary = {
        "run":      run_ts,
        "branch":   BRANCH,
        "analyzed": len(results),
        "ok":       ok_count,
        "issues":   bad_count,
        "dry_run":  args.dry_run,
        "report":   str(report_path.relative_to(REPO_DIR)) if not args.dry_run else None,
        "details":  [
            {
                "file":    r["fichier"],
                "statut":  r.get("statut"),
                "score":   r.get("score_qualité"),
                "résumé":  r.get("résumé", ""),
            }
            for r in results
        ]
    }

    print("\n" + json.dumps(summary, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    main()
