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

Enhancements: Hebbian promotion (#11-12), LTD archival (#13),
Conflict detection (#17, #26), Pruning review (#14).

Usage:
    python .claude/automation/refactor_daemon.py --check
    python .claude/automation/refactor_daemon.py --execute [--dry-run]
    python .claude/automation/refactor_daemon.py --hebbian [--dry-run]
    python .claude/automation/refactor_daemon.py --archive-weak [--dry-run]
    python .claude/automation/refactor_daemon.py --conflicts
Dependencies: Python stdlib only (Law 4)
"""

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

# Add Utilities to path for brain_utils

from pulse.core.brain_utils import (load_config, load_json, save_json, load_json_dict,
                         count_lines, backup_file, text_similarity,
                         EVIDENCE_DIR, PATTERNS_DIR, DOMAINS_DIR,
                         ARCHIVE_DIR, REFACTOR_LOG)


def check_evidence_threshold(path: Path, threshold: int) -> dict:
    items = load_json(path)
    if not isinstance(items, list):
        return {"trigger": False}
    c = len(items)
    return {"file": path.name, "type": "evidence", "count": c,
            "threshold": threshold, "trigger": c >= threshold,
            "percent": round(c / threshold * 100, 1)}


def check_line_threshold(path: Path, threshold: int, ftype: str) -> dict:
    c = count_lines(path)
    return {"file": path.name, "type": ftype, "count": c,
            "threshold": threshold, "trigger": c >= threshold,
            "percent": round(c / threshold * 100, 1) if threshold else 0}


def run_checks() -> list:
    config = load_config()
    ref = config.get("refactoring", {})
    results = []
    if EVIDENCE_DIR.exists():
        t = ref.get("evidence_split_threshold", 200)
        for ef in sorted(EVIDENCE_DIR.rglob("*.json")):
            results.append(check_evidence_threshold(ef, t))
    if PATTERNS_DIR.exists():
        t = ref.get("pattern_split_threshold", 300)
        for pf in sorted(PATTERNS_DIR.rglob("*.md")):
            if pf.name != "patterns.md":
                results.append(check_line_threshold(pf, t, "pattern"))
    if DOMAINS_DIR.exists():
        t = ref.get("domain_split_threshold", 150)
        for df in sorted(DOMAINS_DIR.rglob("*.md")):
            results.append(check_line_threshold(df, t, "domain"))
    return [r for r in results if r.get("file")]


# === HEBBIAN PROMOTION (#11-12) ===

def hebbian_promote(dry_run: bool = False) -> list:
    """Move frequently-referenced patterns to top of files."""
    promotions = []
    if not PATTERNS_DIR.exists():
        return promotions
    pattern_refs = {}
    if EVIDENCE_DIR.exists():
        for ef in sorted(EVIDENCE_DIR.rglob("*.json")):
            items = load_json(ef)
            if isinstance(items, list):
                for item in items:
                    p = item.get("pattern", "")
                    if p:
                        pattern_refs[p] = pattern_refs.get(p, 0) + 1
    config = load_config()
    threshold = config.get("hebbian", {}).get("promotion_threshold", 5)

    for pf in sorted(PATTERNS_DIR.rglob("*.md")):
        if pf.name == "patterns.md":
            continue
        with open(pf, "r", encoding="utf-8") as f:
            content = f.read()
        sections, current_h, current_l = [], None, []
        for line in content.splitlines():
            if line.startswith("## "):
                if current_h:
                    sections.append((current_h, current_l))
                current_h = line[3:].strip()
                current_l = [line]
            else:
                current_l.append(line)
                if not current_h:
                    current_h = "_preamble"
        if current_h:
            sections.append((current_h, current_l))

        preamble, pat_sections = [], []
        for name, lines in sections:
            if name == "_preamble":
                preamble = lines
            else:
                pat_sections.append((name, lines, pattern_refs.get(name, 0)))
        if not pat_sections:
            continue
        sorted_s = sorted(pat_sections, key=lambda x: -x[2])
        if [s[0] for s in pat_sections] != [s[0] for s in sorted_s]:
            promoted = [(n, r) for n, _, r in sorted_s if r >= threshold]
            if promoted:
                promotions.append({"file": pf.name, "promoted": promoted})
                if not dry_run:
                    new_content = chr(10).join(preamble) + chr(10)
                    for _, lines, _ in sorted_s:
                        new_content += chr(10).join(lines) + chr(10)
                    pf.write_text(new_content, encoding="utf-8")
                    print(f"  [HEBBIAN] {pf.name}: Reordered by frequency")
    return promotions


# === LTD ARCHIVAL (#13) ===

def archive_weak(dry_run: bool = False) -> list:
    """Move old low-confidence evidence to archive/."""
    ARCHIVE_DIR.mkdir(parents=True, exist_ok=True)
    archived = []
    config = load_config()
    days_t = config.get("pruning", {}).get("archive_after_days_unused", 60)
    min_conf = config.get("pruning", {}).get("never_prune_high_confidence", 0.95)
    now = datetime.now(timezone.utc)
    if not EVIDENCE_DIR.exists():
        return archived
    for ef in sorted(EVIDENCE_DIR.rglob("*.json")):
        items = load_json(ef)
        if not isinstance(items, list):
            continue
        keep, to_archive = [], []
        for item in items:
            if item.get("confidence", 0.5) >= min_conf:
                keep.append(item); continue
            ts = item.get("date") or item.get("timestamp")
            if not ts:
                keep.append(item); continue
            try:
                ts_str = str(ts).replace("Z", "+00:00")
                d = datetime.fromisoformat(ts_str) if "T" in ts_str else \
                    datetime.fromisoformat(ts_str).replace(tzinfo=timezone.utc)
                days_old = (now - d).days
            except (ValueError, TypeError):
                keep.append(item); continue
            if days_old >= days_t and item.get("confidence", 0.5) < 0.5:
                to_archive.append(item)
            else:
                keep.append(item)
        if to_archive:
            archived.append({"file": ef.name, "count": len(to_archive)})
            if not dry_run:
                ap = ARCHIVE_DIR / f"archived_{ef.name}"
                existing = load_json(ap)
                existing = existing if isinstance(existing, list) else []
                existing.extend(to_archive)
                save_json(ap, existing)
                save_json(ef, keep)
                print(f"  [ARCHIVE] {ef.name}: {len(to_archive)} items")
    return archived


# === CONFLICT DETECTION (#17, #26) ===

def detect_conflicts() -> list:
    conflicts = []
    if not EVIDENCE_DIR.exists():
        return conflicts
    domain_items = {}
    for ef in sorted(EVIDENCE_DIR.glob("*.json")):
        items = load_json(ef)
        if not isinstance(items, list):
            continue
        domain = ef.stem.split("_")[0]
        domain_items.setdefault(domain, []).extend(items)
    for domain, items in domain_items.items():
        wins = [i for i in items if i.get("type") == "win"]
        fails = [i for i in items if i.get("type") == "fail"]
        for w in wins:
            for f in fails:
                sim = text_similarity(w.get("evidence", ""), f.get("evidence", ""))
                if sim > 0.5:
                    conflicts.append({"domain": domain, "similarity": round(sim, 3),
                                      "win": w.get("evidence", "")[:80],
                                      "fail": f.get("evidence", "")[:80]})
    return conflicts


def print_status(results: list):
    print("=== Memory Threshold Status ===")
    for r in sorted(results, key=lambda x: x.get("percent", 0), reverse=True):
        pct = r.get("percent", 0)
        flag = "!!!" if pct >= 100 else "!! " if pct >= 75 else "   "
        filled = int(min(pct, 100) / 5)
        bar = "#" * filled + "." * (20 - filled)
        print(f"  [{flag}] {r['file']:40s} [{bar}] {r['count']:>4d}/{r['threshold']} ({pct:.0f}%)")


def main():
    dry_run = "--dry-run" in sys.argv
    print("=== Brain Refactoring Daemon V43.11 ===")
    if "--hebbian" in sys.argv:
        hebbian_promote(dry_run=dry_run); return
    if "--archive-weak" in sys.argv:
        archive_weak(dry_run=dry_run); return
    if "--conflicts" in sys.argv:
        c = detect_conflicts()
        print(f"  {len(c)} conflict(s)")
        for x in c:
            print(f"  [{x['domain']}] {x['similarity']:.0%}: {x['win'][:50]}"); return
    results = run_checks()
    print_status(results)


if __name__ == "__main__":
    main()
