"""
Brain Learn — LLM-Powered Deep Behavioral Profile Extractor
=============================================================
Uses GPT-4.1-mini to extract deep behavioral insights from session summaries
and update the master brain profile with nuanced understanding that regex cannot capture.

This is the Hermes-inspired deep learning layer for the master brain ONLY.
Per-chat memory stays local and private. Only master brain updates use LLM.

The LLM call is small (200-300 word summary in, structured JSON out).
OpenAI API key is pre-configured in the Manus sandbox environment.

COMMANDS:
  python3 brain_learn.py analyze "<session summary>"
  python3 brain_learn.py analyze-file <text-file>
  python3 brain_learn.py synthesize          - Cross-session synthesis from full profile
  python3 brain_learn.py status              - Show last analysis metadata
"""

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

BRAIN_DIR = Path.home() / ".manus-memory" / "master-brain"
PROFILE_FILE = BRAIN_DIR / "profile.md"
LEARN_LOG = BRAIN_DIR / "learn_log.json"
BRAIN_SCRIPT = Path(__file__).parent / "brain.py"

SYSTEM_PROMPT = """You are a behavioral analyst building a deep psychological and working profile of a user based on their interactions with an AI assistant called Manus.

Your job is to extract DEEP INSIGHTS — not surface facts, but patterns, preferences, frustrations, working style, and behavioral tendencies that will help Manus work better with this specific person.

Focus on:
- HOW they communicate (direct, indirect, frustrated, patient, etc.)
- WHAT frustrates them and WHY
- HOW they think (systems thinker, detail-oriented, big picture, etc.)
- WHAT they value in a collaborator (speed, accuracy, autonomy, explanation, etc.)
- PATTERNS in how they give feedback
- THINGS they should never have to repeat
- IMPLICIT preferences they show but do not explicitly state

Return a JSON object with these exact keys:
{
  "communication_style": ["insight 1", "insight 2"],
  "working_preferences": ["insight 1", "insight 2"],
  "technical_profile": ["insight 1", "insight 2"],
  "do_not_forget": ["critical thing 1", "critical thing 2"],
  "things_learned": ["learning 1", "learning 2"],
  "relationship_note": "one sentence about the state of the relationship and what matters most to this user right now"
}

Be specific and actionable. Not "user prefers efficiency" but "user gets frustrated when asked to confirm things they already said — just do it without asking again."
Only include insights that are genuinely useful. Return empty arrays for categories with nothing meaningful.
"""


def call_llm(session_text: str) -> dict | None:
    """Call GPT-4.1-mini to extract behavioral insights from session text."""
    try:
        from openai import OpenAI
        client = OpenAI()  # Uses OPENAI_API_KEY from environment

        response = client.chat.completions.create(
            model="gpt-4.1-mini",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": f"Analyze this session and extract behavioral insights:\n\n{session_text[:3000]}"}
            ],
            response_format={"type": "json_object"},
            temperature=0.3,
            max_tokens=1000,
        )

        raw = response.choices[0].message.content
        return json.loads(raw)

    except ImportError:
        print("Installing openai package...")
        subprocess.run([sys.executable, "-m", "pip", "install", "openai", "-q"])
        from openai import OpenAI
        client = OpenAI()
        response = client.chat.completions.create(
            model="gpt-4.1-mini",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": f"Analyze this session and extract behavioral insights:\n\n{session_text[:3000]}"}
            ],
            response_format={"type": "json_object"},
            temperature=0.3,
            max_tokens=1000,
        )
        return json.loads(response.choices[0].message.content)

    except Exception as e:
        print(f"LLM call failed: {e}")
        return None


def apply_insights(insights: dict):
    """Apply extracted insights to the master brain profile via brain.py."""
    if not BRAIN_SCRIPT.exists():
        print("brain.py not found.")
        return

    applied = 0

    def run_brain(cmd, *args):
        result = subprocess.run(
            [sys.executable, str(BRAIN_SCRIPT), cmd] + list(args),
            capture_output=True, text=True, timeout=20, input="yes\n"
        )
        return result.stdout

    # Apply communication style insights
    for insight in insights.get("communication_style", [])[:3]:
        if len(insight) > 10:
            out = run_brain("update", "Communication Style", f"[Deep Learning] {insight}")
            if "updated" in out.lower():
                applied += 1
                print(f"  Communication: {insight[:70]}...")

    # Apply working preferences
    for insight in insights.get("working_preferences", [])[:3]:
        if len(insight) > 10:
            out = run_brain("update", "Working Preferences", f"[Deep Learning] {insight}")
            if "updated" in out.lower():
                applied += 1
                print(f"  Preferences: {insight[:70]}...")

    # Apply technical profile
    for insight in insights.get("technical_profile", [])[:2]:
        if len(insight) > 10:
            out = run_brain("update", "Technical Profile", f"[Deep Learning] {insight}")
            if "updated" in out.lower():
                applied += 1
                print(f"  Technical: {insight[:70]}...")

    # Apply do not forget items
    for item in insights.get("do_not_forget", [])[:3]:
        if len(item) > 10:
            out = run_brain("update", "Do Not Forget", f"[Critical] {item}")
            if "updated" in out.lower():
                applied += 1
                print(f"  Do Not Forget: {item[:70]}...")

    # Apply general learnings
    for learning in insights.get("things_learned", [])[:3]:
        if len(learning) > 10:
            out = run_brain("learn", f"[Deep Learning] {learning}")
            applied += 1
            print(f"  Learned: {learning[:70]}...")

    # Apply relationship note
    rel_note = insights.get("relationship_note", "")
    if rel_note and len(rel_note) > 10:
        out = run_brain("history", f"[Auto-synthesized] {rel_note}")
        applied += 1
        print(f"  Relationship: {rel_note[:70]}...")

    return applied


def log_analysis(session_text: str, insights: dict, applied: int):
    """Log the analysis for audit trail."""
    BRAIN_DIR.mkdir(parents=True, exist_ok=True)
    log = []
    if LEARN_LOG.exists():
        try:
            log = json.loads(LEARN_LOG.read_text())
        except Exception:
            log = []

    log.append({
        "timestamp": datetime.now().isoformat(),
        "session_length": len(session_text),
        "insights_extracted": {k: len(v) if isinstance(v, list) else 1
                               for k, v in insights.items() if v},
        "applied_count": applied,
    })

    # Keep last 50 entries only
    LEARN_LOG.write_text(json.dumps(log[-50:], indent=2))


def cmd_analyze(session_text: str):
    """Analyze session text with LLM and update master brain."""
    if len(session_text.strip()) < 50:
        print("Session text too short to analyze meaningfully.")
        return

    print("\nBrain Learn: analyzing session with GPT-4.1-mini...")
    print(f"Session length: {len(session_text)} characters")
    print("Extracting behavioral insights...\n")

    insights = call_llm(session_text)

    if not insights:
        print("Could not extract insights. Check your OpenAI API key.")
        return

    print("Insights extracted. Applying to master brain profile:\n")
    applied = apply_insights(insights)
    log_analysis(session_text, insights, applied)

    if applied > 0:
        print(f"\nBrain Learn complete: {applied} deep insights added to master brain.")
        print("Profile saved to self-hosted server automatically.")
    else:
        print("\nNo new insights to apply (may already be in profile).")


def cmd_synthesize():
    """Cross-session synthesis — read full profile and ask LLM to identify gaps and patterns."""
    if not PROFILE_FILE.exists():
        print("No master brain profile found.")
        return

    profile_text = PROFILE_FILE.read_text()

    print("\nBrain Learn: running cross-session synthesis...")

    synthesis_prompt = """You are reviewing a user's master brain profile built up over multiple sessions with an AI assistant.

Identify:
1. Any contradictions or outdated information
2. Patterns that are implied but not explicitly stated
3. The most important things this user needs from their AI assistant
4. Gaps in the profile that should be filled

Return JSON:
{
  "key_patterns": ["pattern 1", "pattern 2"],
  "most_important": "the single most important thing to remember about this user",
  "gaps": ["gap 1", "gap 2"],
  "do_not_forget": ["critical item 1"]
}"""

    try:
        from openai import OpenAI
        client = OpenAI()
        response = client.chat.completions.create(
            model="gpt-4.1-mini",
            messages=[
                {"role": "system", "content": synthesis_prompt},
                {"role": "user", "content": f"Synthesize this profile:\n\n{profile_text[:4000]}"}
            ],
            response_format={"type": "json_object"},
            temperature=0.3,
            max_tokens=800,
        )
        synthesis = json.loads(response.choices[0].message.content)

        print("\nSynthesis complete:\n")

        most_important = synthesis.get("most_important", "")
        if most_important:
            print(f"Most important: {most_important}")

        for pattern in synthesis.get("key_patterns", [])[:3]:
            print(f"Pattern: {pattern}")

        for gap in synthesis.get("gaps", [])[:3]:
            print(f"Gap identified: {gap}")

        # Apply do_not_forget items
        for item in synthesis.get("do_not_forget", [])[:2]:
            subprocess.run(
                [sys.executable, str(BRAIN_SCRIPT), "update", "Do Not Forget", f"[Synthesis] {item}"],
                capture_output=True, text=True, timeout=20, input="yes\n"
            )
            print(f"Added to Do Not Forget: {item[:60]}...")

        print("\nSynthesis applied to master brain.")

    except Exception as e:
        print(f"Synthesis failed: {e}")


def cmd_status():
    """Show last analysis metadata."""
    if not LEARN_LOG.exists():
        print("No analysis history yet. Run: python3 brain_learn.py analyze '<session text>'")
        return

    try:
        log = json.loads(LEARN_LOG.read_text())
    except Exception:
        print("Could not read analysis log.")
        return

    print(f"\nBrain Learn — Analysis History ({len(log)} sessions analyzed)\n")
    print(f"{'TIMESTAMP':<22} {'SESSION LEN':<14} {'INSIGHTS':<10} {'APPLIED'}")
    print("─" * 60)
    for entry in log[-10:]:
        ts = entry.get("timestamp", "")[:16]
        slen = entry.get("session_length", 0)
        insights = sum(entry.get("insights_extracted", {}).values())
        applied = entry.get("applied_count", 0)
        print(f"{ts:<22} {slen:<14} {insights:<10} {applied}")

    print(f"\nLast {min(10, len(log))} of {len(log)} total analyses shown.")


def main():
    args = sys.argv[1:]
    if not args:
        print(__doc__)
        return

    cmd = args[0]

    if cmd == "analyze" and len(args) >= 2:
        cmd_analyze(" ".join(args[1:]))
    elif cmd == "analyze-file" and len(args) >= 2:
        text_file = Path(args[1])
        if text_file.exists():
            cmd_analyze(text_file.read_text())
        else:
            print(f"File not found: {text_file}")
    elif cmd == "synthesize":
        cmd_synthesize()
    elif cmd == "status":
        cmd_status()
    else:
        print(__doc__)


if __name__ == "__main__":
    main()
