#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Private Brain Synthesis: Consolidate private learnings into patterns.

Scans Hippocampus/Private/ for lessons, evidence, and notes.
Extracts recurring themes and writes synthesized patterns to
Hippocampus/Private/private_patterns.md.

Run manually or scheduled by orchestrator (every 24h).
Dependencies: Python stdlib only (Law 4)
"""

import json
import re
import sys
from collections import Counter
from datetime import datetime, timezone
from pathlib import Path

SCRIPT_DIR = Path(__file__).resolve().parent
ROOT_DIR = SCRIPT_DIR.parent.parent.parent
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

from pulse.core.brain_utils import HIPPOCAMPUS_DIR

PRIVATE_DIR = HIPPOCAMPUS_DIR / "Private"
LESSONS_FILE = PRIVATE_DIR / "private_lessons.md"
EVIDENCE_FILE = PRIVATE_DIR / "private_evidence.json"
NOTES_FILE = PRIVATE_DIR / "notes.md"
PATTERNS_FILE = PRIVATE_DIR / "private_patterns.md"

# Words to ignore when finding themes
_STOP_WORDS = frozenset({
    "the", "a", "an", "is", "was", "are", "were", "be", "been",
    "have", "has", "had", "do", "does", "did", "will", "would",
    "could", "should", "may", "might", "can", "shall", "to", "of",
    "in", "for", "on", "with", "at", "by", "from", "as", "into",
    "through", "during", "before", "after", "above", "below",
    "between", "under", "again", "further", "then", "once", "that",
    "this", "these", "those", "it", "its", "not", "no", "nor",
    "but", "or", "and", "if", "so", "than", "too", "very",
    "just", "about", "also", "more", "some", "any", "each",
    "which", "who", "what", "when", "where", "how", "why",
    "all", "both", "other", "such", "only",
})


def _extract_sections(md_text: str) -> list[str]:
    """Extract section bodies from markdown (split on ## headers)."""
    sections = re.split(r'^## ', md_text, flags=re.MULTILINE)
    results = []
    for section in sections[1:]:  # Skip preamble
        lines = section.strip().split("\n")
        body = "\n".join(lines[1:]).strip()  # Skip title line
        # Remove metadata lines
        body = re.sub(r'\*\*Source:\*\*.*$', '', body, flags=re.MULTILINE)
        body = re.sub(r'\*\*Date:\*\*.*$', '', body, flags=re.MULTILINE)
        body = body.strip(" \n-")
        if body and len(body) > 20:
            results.append(body)
    return results


def _extract_themes(texts: list[str], min_count: int = 2) -> list[tuple[str, int]]:
    """Find recurring 2-3 word phrases across texts."""
    phrase_counts = Counter()
    for text in texts:
        words = [w.lower().strip(".,;:!?()\"'") for w in text.split()
                 if len(w) > 3 and w.lower() not in _STOP_WORDS]
        # Bigrams
        for i in range(len(words) - 1):
            phrase = f"{words[i]} {words[i+1]}"
            phrase_counts[phrase] += 1
        # Trigrams
        for i in range(len(words) - 2):
            phrase = f"{words[i]} {words[i+1]} {words[i+2]}"
            phrase_counts[phrase] += 1

    return [(phrase, count) for phrase, count in phrase_counts.most_common(20)
            if count >= min_count]


def _cluster_by_theme(texts: list[str], themes: list[tuple[str, int]]) -> dict[str, list[str]]:
    """Group texts by which theme they match."""
    clusters = {}
    assigned = set()
    for phrase, _ in themes:
        cluster = []
        for i, text in enumerate(texts):
            if i in assigned:
                continue
            if phrase in text.lower():
                cluster.append(text)
                assigned.add(i)
        if cluster:
            clusters[phrase] = cluster
    return clusters


def synthesize() -> dict:
    """
    Main synthesis: read private lessons/evidence/notes, find patterns,
    write synthesized patterns to private_patterns.md.

    Returns dict with synthesis stats.
    """
    PRIVATE_DIR.mkdir(parents=True, exist_ok=True)
    all_texts = []

    # 1. Read private lessons
    if LESSONS_FILE.exists():
        content = LESSONS_FILE.read_text(encoding="utf-8", errors="replace")
        all_texts.extend(_extract_sections(content))

    # 2. Read private evidence
    if EVIDENCE_FILE.exists():
        try:
            items = json.loads(EVIDENCE_FILE.read_text(encoding="utf-8"))
            if isinstance(items, list):
                for item in items:
                    text = item.get("description", "") or item.get("text", "")
                    if text and len(text) > 20:
                        all_texts.append(text)
        except (json.JSONDecodeError, Exception):
            pass

    # 3. Read notes
    if NOTES_FILE.exists():
        content = NOTES_FILE.read_text(encoding="utf-8", errors="replace")
        sections = _extract_sections(content)
        all_texts.extend(sections)

    results = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "texts_analyzed": len(all_texts),
        "themes_found": 0,
        "patterns_written": 0,
    }

    if len(all_texts) < 2:
        return results

    # 4. Find recurring themes
    themes = _extract_themes(all_texts)
    results["themes_found"] = len(themes)

    if not themes:
        return results

    # 5. Cluster texts by theme
    clusters = _cluster_by_theme(all_texts, themes)

    # 6. Write synthesized patterns
    now = datetime.now(timezone.utc)
    header = f"---\ntype: private-synthesis\nlast_updated: {now.strftime('%Y-%m-%d')}\n---\n\n"
    header += "# Private Patterns (Auto-Synthesized)\n\n"
    header += "> Synthesized from private lessons, evidence, and notes.\n"
    header += f"> Last run: {now.strftime('%Y-%m-%d %H:%M UTC')}\n\n---\n"

    parts = [header]
    for theme, texts in clusters.items():
        parts.append(f"\n\n## Theme: {theme.title()}")
        parts.append(f"\n*Frequency: {len(texts)} occurrences*\n")
        for text in texts[:3]:  # Max 3 examples per theme
            summary = text[:200].strip()
            parts.append(f"- {summary}")
        parts.append("\n---")
        results["patterns_written"] += 1

    PATTERNS_FILE.write_text("\n".join(parts), encoding="utf-8")
    return results


if __name__ == "__main__":
    result = synthesize()
    print(json.dumps(result, indent=2))
