#!/usr/bin/env python3
"""
Aria Self-Audit Meta-Agent
Analysiert 7 Tage Chat (Supabase) + Memory + CORRECTIONS.md.
Erkennt Muster: Wiederholungs-Fehler, Frust-Signale, ungehaltene Versprechen.
Sendet Report via Telegram an Kais (kein LLM-Call, nur Heuristik).

Usage: python3 aria-self-audit.py [days]
  Default: 7 Tage
"""
import os
import re
import sys
import json
import urllib.request
from datetime import datetime, timezone, timedelta
from collections import Counter

DAYS = int(sys.argv[1]) if len(sys.argv) > 1 else 7
BRAIN = "/root/aria/brain"
MEMORY_DIR = "/root/.claude/projects/-/memory"
CORRECTIONS = f"{BRAIN}/CORRECTIONS.md"


def load_env():
    env_files = ["/root/aria/.env", "/root/aria/scripts/.env.aria",
                 "/root/.claude/channels/telegram/.env", "/root/.claude/.env"]
    for f in env_files:
        if not os.path.exists(f):
            continue
        with open(f) as fh:
            for line in fh:
                line = line.strip()
                if "=" in line and not line.startswith("#"):
                    k, _, v = line.partition("=")
                    if k and k not in os.environ:
                        os.environ[k] = v.strip('"').strip("'")


def fetch_chat_supabase(days):
    url = os.environ.get("SUPABASE_URL") or os.environ.get("NEXT_PUBLIC_SUPABASE_URL")
    key = os.environ.get("SUPABASE_SERVICE_ROLE_KEY") or os.environ.get("SUPABASE_KEY")
    if not url or not key:
        return []
    cutoff = (datetime.now(timezone.utc) - timedelta(days=days)).strftime("%Y-%m-%dT%H:%M:%SZ")
    req_url = (
        f"{url}/rest/v1/aria_chat_log"
        f"?select=created_at,direction,user_name,message_text"
        f"&created_at=gte.{cutoff}"
        f"&order=created_at.asc"
        f"&limit=5000"
    )
    req = urllib.request.Request(
        req_url,
        headers={"apikey": key, "Authorization": f"Bearer {key}"},
    )
    try:
        with urllib.request.urlopen(req, timeout=15) as r:
            rows = json.loads(r.read())
            # Normalize to role/content
            for r_ in rows:
                r_["role"] = "user" if r_.get("direction") == "in" else "assistant"
                r_["content"] = r_.get("message_text") or ""
            return rows
    except Exception as e:
        print(f"[supabase err: {e}]", file=sys.stderr)
        return []


FRUSTRATION_PATTERNS = [
    (r"\b(nein)\b", "nein"),
    (r"\b(stop|stopp)\b", "stop"),
    (r"\b(falsch|verkehrt)\b", "falsch"),
    (r"hast du .*nicht|nicht gemacht", "nicht gemacht"),
    (r"\?\?+|!!+", "ausruf/fragezeichen-ballung"),
    (r"warum (kommst|machst|hast)", "warum nicht proaktiv"),
    (r"hatte dich .*gebeten|schon oft|wieder mal", "wiederholte bitte"),
    (r"sowas (kommt|höre) .*oft von dir", "ungehaltene versprechen"),
    (r"(müll|scheiße|kacke|mist)", "frustausdruck"),
    (r"kam .*nicht an|erreicht mich nicht|in whatsapp .*nicht", "kommunikations-fehlschlag"),
]

PROMISE_PATTERNS = [
    r"ich (werde|mache|leg(e)? los|kümmere mich)",
    r"ab jetzt|ab sofort|künftig|zukünftig",
    r"verspreche|versprochen",
    r"meld(e)? (mich|ich) (sobald|wenn|bei)",
]


def analyze_chat(messages):
    if not messages:
        return {}
    total = len(messages)
    user_msgs = [m for m in messages if m.get("role") in ("user", "human")]
    aria_msgs = [m for m in messages if m.get("role") in ("assistant", "aria", "claude")]

    frust_hits = Counter()
    for m in user_msgs:
        c = (m.get("content") or "").lower()
        for pat, label in FRUSTRATION_PATTERNS:
            if re.search(pat, c):
                frust_hits[label] += 1

    aria_promises = 0
    for m in aria_msgs:
        c = (m.get("content") or "").lower()
        for pat in PROMISE_PATTERNS:
            if re.search(pat, c):
                aria_promises += 1
                break

    pii_leak_suspects = 0
    for m in aria_msgs:
        c = m.get("content") or ""
        if re.search(r"[\w.+-]+@[\w-]+\.[\w.-]+", c) and "telegram" in (m.get("content") or "").lower():
            pii_leak_suspects += 1

    return {
        "total_msgs": total,
        "user_msgs": len(user_msgs),
        "aria_msgs": len(aria_msgs),
        "frust_hits": dict(frust_hits),
        "aria_promises": aria_promises,
        "pii_leak_suspects": pii_leak_suspects,
    }


def analyze_corrections():
    if not os.path.exists(CORRECTIONS):
        return {"exists": False}
    with open(CORRECTIONS) as f:
        content = f.read()
    return {
        "exists": True,
        "size_kb": round(len(content) / 1024, 1),
        "entries": len(re.findall(r"^#{1,3} ", content, re.MULTILINE)),
    }


def analyze_memory():
    if not os.path.isdir(MEMORY_DIR):
        return {"count": 0}
    files = [f for f in os.listdir(MEMORY_DIR) if f.endswith(".md") and f != "MEMORY.md"]
    types = Counter()
    for f in files:
        with open(os.path.join(MEMORY_DIR, f)) as fh:
            head = fh.read(400)
            m = re.search(r"type:\s*(\w+)", head)
            if m:
                types[m.group(1)] += 1
    return {"count": len(files), "by_type": dict(types)}


def brain_health():
    try:
        import subprocess
        out = subprocess.run(["bash", "/root/aria/scripts/aria-brain-health.sh"], capture_output=True, text=True, timeout=30)
        return out.stdout
    except Exception as e:
        return f"[brain-health err: {e}]"


def build_report(chat_stats, corr_stats, mem_stats, brain_report, days):
    now = datetime.now(timezone.utc).astimezone()
    lines = []
    lines.append(f"🔍 ARIA SELF-AUDIT — {now.strftime('%d.%m.%Y %H:%M')}")
    lines.append(f"Zeitraum: letzte {days} Tage")
    lines.append("")

    if chat_stats:
        lines.append(f"📊 Chat: {chat_stats['total_msgs']} Nachrichten "
                     f"({chat_stats['user_msgs']} Kais / {chat_stats['aria_msgs']} Aria)")
        if chat_stats["frust_hits"]:
            lines.append("")
            lines.append("⚠️ Frust-Signale von Kais:")
            for label, n in sorted(chat_stats["frust_hits"].items(), key=lambda x: -x[1]):
                lines.append(f"  • {label}: {n}×")
        lines.append(f"💬 Aria-Versprechen gezählt: {chat_stats['aria_promises']}")
        if chat_stats.get("pii_leak_suspects"):
            lines.append(f"🚨 PII-Leak-Verdachtsfälle (Mails via Telegram): {chat_stats['pii_leak_suspects']}")
    else:
        lines.append("📊 Chat: keine Daten (Supabase nicht erreichbar oder leer)")

    lines.append("")
    lines.append(f"🧠 Memory: {mem_stats['count']} Dateien — {mem_stats.get('by_type', {})}")

    if corr_stats["exists"]:
        lines.append(f"📝 CORRECTIONS.md: {corr_stats['entries']} Einträge ({corr_stats['size_kb']} KB)")
    else:
        lines.append("📝 CORRECTIONS.md: nicht gefunden")

    lines.append("")
    lines.append("🕸️ Brain-Graph:")
    for l in (brain_report or "").splitlines():
        if l.strip() and not l.startswith("==="):
            lines.append(f"  {l}")

    # Verbesserungs-Hypothesen
    lines.append("")
    lines.append("💡 Auffälligkeiten (zur Prüfung durch Kais):")
    if chat_stats.get("frust_hits", {}).get("ungehaltene versprechen", 0) > 0 or \
       chat_stats.get("frust_hits", {}).get("wiederholte bitte", 0) > 0:
        lines.append("  • Kais weist auf wiederholte/ungehaltene Zusagen hin — Memory-Regeln ggf. technisch durch Hooks erzwingen")
    if chat_stats.get("aria_promises", 0) > 15:
        lines.append("  • Aria macht viele Zusagen — prüfen ob jede tatsächlich umgesetzt wurde")
    if chat_stats.get("frust_hits", {}).get("kommunikations-fehlschlag", 0) > 0:
        lines.append("  • Telegram-Versand-Fehler — reply tool Disziplin checken")
    if chat_stats.get("frust_hits", {}).get("warum nicht proaktiv", 0) > 0:
        lines.append("  • Kais fordert proaktives Denken — neue Checkroutinen im Abendbericht verankern")
    if "Orphans (kein[[]]):" in (brain_report or "") and "Orphans (kein[[]]):0" not in (brain_report or ""):
        lines.append("  • Brain hat Orphan-Notizen — Wikilink-Audit ausführen")

    lines.append("")
    lines.append("ℹ️ Report generiert von /root/aria/scripts/aria-self-audit.py")
    lines.append("   Umsetzungen nur nach deiner Freigabe.")
    return "\n".join(lines)


def send_telegram(text):
    token = (os.environ.get("TG_TOKEN") or os.environ.get("TELEGRAM_BOT_TOKEN")
             or os.environ.get("TELEGRAM_TOKEN"))
    chat_id = (os.environ.get("TELEGRAM_OWNER_CHAT_ID") or os.environ.get("TELEGRAM_CHAT_ID")
               or "1164395546")
    if not token:
        print("[telegram-token fehlt]", file=sys.stderr)
        print(text)
        return False
    for chunk_start in range(0, len(text), 4000):
        chunk = text[chunk_start:chunk_start + 4000]
        data = json.dumps({"chat_id": chat_id, "text": chunk}).encode()
        req = urllib.request.Request(
            f"https://api.telegram.org/bot{token}/sendMessage",
            data=data,
            headers={"Content-Type": "application/json"},
        )
        try:
            urllib.request.urlopen(req, timeout=15).read()
        except Exception as e:
            print(f"[telegram err: {e}]", file=sys.stderr)
            return False
    return True


def main():
    load_env()
    chat = fetch_chat_supabase(DAYS)
    chat_stats = analyze_chat(chat)
    corr_stats = analyze_corrections()
    mem_stats = analyze_memory()
    brain_report = brain_health()
    report = build_report(chat_stats, corr_stats, mem_stats, brain_report, DAYS)
    out_path = f"/root/aria/brain/02-Wissen/self-audit-reports/audit-{datetime.now().strftime('%Y-%m-%d')}.md"
    os.makedirs(os.path.dirname(out_path), exist_ok=True)
    with open(out_path, "w") as f:
        f.write(report + "\n")
    print(report)
    send_telegram(report)


if __name__ == "__main__":
    main()
