#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Brain Growth Monitor (Neuroscience-Enhanced V43.11)

Enhancements: Velocity tracking (#21), Transfer metrics (#16),
Meta-pattern analysis (#23), Prediction (#21).

Usage:
    python .claude/automation/growth_monitor.py [--update] [--json]
    python .claude/automation/growth_monitor.py --velocity
    python .claude/automation/growth_monitor.py --predict
Dependencies: Python stdlib only (Law 4)
"""

import json
import sys
from datetime import date, datetime, timezone
from pathlib import Path

from pulse.core.brain_utils import (load_config, load_json, load_json_dict, save_json,
                         count_json_items, count_lines, count_md_sections,
                         EVIDENCE_DIR, PATTERNS_DIR, LESSONS_DIR, DOMAINS_DIR,
                         WINS_DIR, FAILS_DIR, GROWTH_METRICS)


def scan_current_state() -> dict:
    state = {"evidence": {}, "patterns": {}, "lessons": {}, "domains": {},
             "wins": {}, "fails": {}, "totals": {}}
    te, tp, tl, tw, tf = 0, 0, 0, 0, 0
    if EVIDENCE_DIR.exists():
        for ef in sorted(EVIDENCE_DIR.rglob("*.json")):
            c = count_json_items(ef); state["evidence"][ef.name] = c; te += c
    if PATTERNS_DIR.exists():
        for pf in sorted(PATTERNS_DIR.rglob("*.md")):
            if pf.name != "patterns.md":
                s = count_md_sections(pf)
                state["patterns"][pf.name] = {"sections": s, "lines": count_lines(pf)}
                tp += s
    if LESSONS_DIR.exists():
        for lf in sorted(LESSONS_DIR.rglob("*.md")):
            if lf.name != "lessons.md":
                s = count_md_sections(lf); state["lessons"][lf.name] = s; tl += s
    if DOMAINS_DIR.exists():
        for df in sorted(DOMAINS_DIR.rglob("*.md")):
            state["domains"][df.name] = count_lines(df)
    if WINS_DIR.exists():
        for wf in sorted(WINS_DIR.rglob("*_wins.md")):
            s = count_md_sections(wf); state["wins"][wf.name] = s; tw += s
    if FAILS_DIR.exists():
        for ff in sorted(FAILS_DIR.rglob("*_fails.md")):
            s = count_md_sections(ff); state["fails"][ff.name] = s; tf += s
    state["totals"] = {"evidence_items": te, "patterns": tp, "lessons": tl,
                       "wins": tw, "fails": tf,
                       "scan_date": datetime.now(timezone.utc).isoformat()}
    return state


def compute_deltas(current: dict, previous: dict) -> dict:
    deltas = {"evidence": {}, "totals": {}}
    pf = previous.get("files", {})
    for fname, count in current.get("evidence", {}).items():
        pk = f"Raw_Evidence/{fname}"
        prev = pf.get(pk, {}).get("items", 0)
        if count != prev:
            deltas["evidence"][fname] = count - prev
    pt = previous.get("totals", {})
    ct = current.get("totals", {})
    for key in ["evidence_items", "patterns", "lessons", "wins", "fails"]:
        if ct.get(key, 0) != pt.get(key, 0):
            deltas["totals"][key] = ct.get(key, 0) - pt.get(key, 0)
    return deltas


# === VELOCITY (#21) ===

def compute_velocity(metrics: dict) -> dict:
    timing = metrics.get("synthesis_timing", [])
    if not timing:
        return {"patterns_per_day": 0, "days_tracked": 0, "trend": "unknown"}
    dates = set()
    total_p = 0
    for e in timing:
        d = e.get("date", "")[:10]
        if d: dates.add(d)
        total_p += e.get("patterns", 0)
    days = max(len(dates), 1)
    trend = "stable"
    if len(timing) >= 6:
        recent = sum(t.get("patterns", 0) for t in timing[-3:])
        older = sum(t.get("patterns", 0) for t in timing[-6:-3])
        if recent > older * 1.5: trend = "accelerating"
        elif recent < older * 0.5: trend = "decelerating"
    return {"patterns_per_day": round(total_p / days, 2),
            "days_tracked": days, "total_synthesized": total_p, "trend": trend}


# === PREDICTION (#21) ===

def predict_next_synthesis(current: dict, config: dict) -> list:
    predictions = []
    default_t = config.get("synthesis", {}).get("default_threshold", 5)
    domain_t = config.get("synthesis", {}).get("domain_thresholds", {})
    prev = load_json_dict(GROWTH_METRICS).get("files", {})

    for fname in current.get("evidence", {}):
        domain = fname.split("_")[0]
        threshold = domain_t.get(domain, default_t)
        ef_path = EVIDENCE_DIR / fname
        items = load_json(ef_path) if ef_path.exists() else []
        if not isinstance(items, list): continue
        groups = {}
        for item in items:
            p = item.get("pattern", "uncategorized")
            groups.setdefault(p, []).append(item)
        for pname, gitems in groups.items():
            remaining = threshold - len(gitems)
            if remaining <= 0:
                predictions.append({"file": fname, "pattern": pname,
                                    "status": "READY", "items": len(gitems),
                                    "threshold": threshold})
            elif remaining <= 2:
                gr = prev.get(f"evidence/{fname}", {}).get("growth_rate", 0.5)
                est = round(remaining / gr, 1) if gr > 0 else -1
                predictions.append({"file": fname, "pattern": pname,
                                    "status": "APPROACHING", "items": len(gitems),
                                    "threshold": threshold, "remaining": remaining,
                                    "est_days": est})
    return sorted(predictions, key=lambda x: x.get("remaining", 0))


# === TRANSFER (#16) ===

def compute_transfer_metrics() -> dict:
    if not EVIDENCE_DIR.exists():
        return {"cross_domain": 0, "universal": 0}
    pd = {}
    for ef in sorted(EVIDENCE_DIR.rglob("*.json")):
        domain = ef.stem.split("_")[0]
        items = load_json(ef)
        if isinstance(items, list):
            for item in items:
                p = item.get("pattern", "")
                if isinstance(p, dict): # Skip malformed patterns
                    continue
                if p: pd.setdefault(p, set()).add(domain)
    return {"cross_domain": sum(1 for d in pd.values() if len(d) >= 2),
            "universal": sum(1 for d in pd.values() if len(d) >= 3),
            "total_unique": len(pd)}


def update_metrics(current: dict):
    metrics = load_json_dict(GROWTH_METRICS)
    today = date.today().isoformat()
    files = metrics.setdefault("files", {})
    for fname, count in current.get("evidence", {}).items():
        key = f"Raw_Evidence/{fname}"
        prev = files.get(key, {}).get("items", 0)
        try:
            pd = files.get(key, {}).get("last_updated", today)[:10]
            days = max((date.fromisoformat(today) - date.fromisoformat(pd)).days, 1)
        except (ValueError, TypeError):
            days = 1
        files[key] = {"items": count, "growth_rate": round((count - prev) / days, 2),
                      "last_updated": today, "status": "active"}
    for fname, data in current.get("patterns", {}).items():
        key = f"Semantic/{fname}"
        s = data["sections"] if isinstance(data, dict) else 0
        l = data["lines"] if isinstance(data, dict) else 0
        files[key] = {"lines": l, "patterns": s, "last_updated": today, "status": "active"}
    metrics["totals"] = current.get("totals", {})
    metrics["totals"]["scan_date"] = today
    metrics["version"] = "V43.11"
    metrics["velocity"] = compute_velocity(metrics)
    metrics["transfer"] = compute_transfer_metrics()
    save_json(GROWTH_METRICS, metrics)
    print(f"  [UPDATED] _growth_metrics.json")


def print_report(current: dict, deltas: dict):
    t = current.get("totals", {})
    print("=== Brain Growth Report V43.11 ===")
    print(f"  Evidence: {t.get('evidence_items', 0)} | Patterns: {t.get('patterns', 0)} | "
          f"Lessons: {t.get('lessons', 0)} | Wins: {t.get('wins', 0)} | Fails: {t.get('fails', 0)}")
    dt = deltas.get("totals", {})
    if dt:
        print("  Changes: " + ", ".join(f"{k}:{'+' if v>0 else ''}{v}" for k, v in dt.items()))
    v = compute_velocity(load_json_dict(GROWTH_METRICS))
    print(f"  Velocity: {v['patterns_per_day']} patterns/day, trend: {v['trend']}")
    tr = compute_transfer_metrics()
    print(f"  Transfer: {tr['cross_domain']} cross-domain, {tr['universal']} universal")


def main():
    config = load_config()
    current = scan_current_state()
    previous = load_json_dict(GROWTH_METRICS)
    deltas = compute_deltas(current, previous)

    if "--velocity" in sys.argv:
        v = compute_velocity(load_json_dict(GROWTH_METRICS))
        for k, val in v.items(): print(f"  {k}: {val}")
        return
    if "--predict" in sys.argv:
        for p in predict_next_synthesis(current, config):
            print(f"  [{p['status']}] {p['file']}:{p['pattern']} ({p['items']}/{p['threshold']})")
        return
    if "--json" in sys.argv:
        print(json.dumps({"current": current, "deltas": deltas,
                          "velocity": compute_velocity(previous),
                          "transfer": compute_transfer_metrics()}, indent=2))
    else:
        print_report(current, deltas)
    if "--update" in sys.argv:
        update_metrics(current)


if __name__ == "__main__":
    main()
