#!/usr/bin/env python3
"""
Manus Persistent Memory Manager v4
RAG Tier: Advanced + Hybrid + Agentic
"""

import sys
import json
import re
import time
import requests
from pathlib import Path
from datetime import datetime

# Add scripts dir to path
sys.path.insert(0, str(Path(__file__).parent))
from brain_client import (
    save_to_identity, save_secret, save_project_memory, save_fact,
    save_episode, save_decision, save_idea, save_area,
    load_identity, load_secrets, load_project, load_area,
    brain_search, status, index_memory, save_record, get_records,
    find_record
)


def cmd_save(args):
    """Save project memory: save <chat_id> <chat_name> <field> <content>"""
    if len(args) < 4:
        print("Usage: save <chat_id> <chat_name> <field> <content>")
        return
    chat_id, chat_name, field = args[0], args[1], args[2]
    content = " ".join(args[3:])
    result = save_project_memory(chat_id, chat_name, **{field: content})
    print(f"Saved to memory [{chat_name}].")


def cmd_save_full(args):
    """Save full project memory from JSON: save-full <chat_id> <chat_name> <json_file_or_content>"""
    if len(args) < 3:
        print("Usage: save-full <chat_id> <chat_name> <json_file_or_content>")
        return
    chat_id, chat_name = args[0], args[1]
    content = " ".join(args[2:])
    try:
        if Path(content).exists():
            fields = json.loads(Path(content).read_text())
        else:
            fields = json.loads(content)
    except (json.JSONDecodeError, OSError):
        fields = {"current_state": content}

    result = save_project_memory(chat_id, chat_name, **fields)
    print(f"Memory saved [{chat_name}].")


def cmd_load(args):
    """Load project memory: load <chat_id>"""
    if not args:
        print("Usage: load <chat_id>")
        return
    chat_id = args[0]
    record = load_project(chat_id)
    if record:
        print(f"\n{'='*55}")
        print(f"  PROJECT MEMORY: {record.get('chat_name', chat_id)}")
        print(f"{'='*55}")
        for key, val in record.items():
            if key in ("id", "collectionId", "collectionName", "created", "updated"):
                continue
            if val:
                print(f"\n  {key}: {val}")
        print(f"\n{'='*55}")
    else:
        print(f"No memory found for: {chat_id}")


def cmd_save_brain(args):
    """Save to identity: save-brain <section> <content>"""
    if len(args) < 2:
        print("Usage: save-brain <section> <content>")
        return
    section = args[0]
    content = " ".join(args[1:])
    result = save_to_identity(section, content)
    print(f"Saved to brain [{section}].")


def cmd_load_brain(args):
    """Load full identity using agentic search to surface most relevant context."""
    records = load_identity()
    if records:
        print(f"\n{'='*55}")
        print(f"  MASTER BRAIN / IDENTITY")
        print(f"{'='*55}")
        for r in records:
            print(f"\n  === {r.get('section', 'unknown')} ===")
            print(f"  {r.get('content', '')}")
            if r.get('tags'):
                print(f"  Tags: {r.get('tags')}")
        print(f"\n{'='*55}")

        # Agentic search to surface most relevant recent context
        print(f"\n  --- Surfacing relevant context (agentic search) ---")
        try:
            recent = brain_search("current projects goals preferences decisions", mode="agentic", limit=5)
            if recent:
                print(f"  Top {len(recent)} relevant memories:\n")
                for r in recent:
                    score = r.get("score", 0)
                    content = r.get("content", "")[:180]
                    src = r.get("source", "semantic")
                    print(f"    [{score:.3f}|{src}] {content}")
        except Exception:
            pass  # Non-critical, don't fail identity load
        print(f"\n{'='*55}")
    else:
        print("Brain is empty. Start saving with: save-brain <section> <content>")


def cmd_save_secret(args):
    """Save credential: save-secret <name> <value> [category] [service] [notes]"""
    if len(args) < 2:
        print("Usage: save-secret <name> <value> [category] [service] [notes]")
        return
    name, value = args[0], args[1]
    category = args[2] if len(args) > 2 else "other"
    service = args[3] if len(args) > 3 else ""
    notes = " ".join(args[4:]) if len(args) > 4 else ""
    result = save_secret(name, value, category, service, notes)
    print(f"Credential saved [{name}].")


def cmd_load_secrets(args):
    """Load secrets. Values masked by default. Use 'reveal' to show actual values."""
    reveal = "reveal" in args or "show" in args
    records = load_secrets()
    if records:
        print(f"\n{'='*55}")
        print(f"  CREDENTIALS ({len(records)} active)")
        if not reveal:
            print(f"  (values masked - use 'load-secrets reveal' to show)")
        print(f"{'='*55}")
        for r in records:
            name = r.get('name', '?')
            category = r.get('category', '?')
            service = r.get('related_service', '')
            if reveal:
                val = r.get('value', '')
            else:
                raw = r.get('value', '')
                if len(raw) <= 4:
                    val = '****'
                else:
                    val = raw[:2] + '****' + raw[-2:]
            svc_str = f" ({service})" if service else ""
            print(f"  [{category}] {name}: {val}{svc_str}")
        print(f"{'='*55}")
    else:
        print("No credentials stored yet.")


def cmd_save_fact(args):
    """Save fact: save-fact <category> <fact>"""
    if len(args) < 2:
        print("Usage: save-fact <category> <fact>")
        return
    category = args[0]
    fact = " ".join(args[1:])
    result = save_fact(fact, category)
    print(f"Fact saved [{category}].")


def cmd_save_decision(args):
    """Save decision: save-decision <decision> | <reasoning>"""
    if not args:
        print("Usage: save-decision <decision> | <reasoning>")
        return
    full = " ".join(args)
    parts = full.split("|")
    decision = parts[0].strip()
    reasoning = parts[1].strip() if len(parts) > 1 else ""
    result = save_decision(decision, reasoning)
    print(f"Decision saved.")


def cmd_save_idea(args):
    """Save idea: save-idea <category> <title> | <description>"""
    if len(args) < 2:
        print("Usage: save-idea <category> <title> | <description>")
        return
    category = args[0]
    full = " ".join(args[1:])
    parts = full.split("|")
    title = parts[0].strip()
    description = parts[1].strip() if len(parts) > 1 else ""
    result = save_idea(title, description, category)
    print(f"Idea saved [{category}].")


def cmd_save_area(args):
    """Save to life area: save-area <area> <topic> <content>"""
    if len(args) < 3:
        print("Usage: save-area <tech|business|people|personal> <topic> <content>")
        return
    area, topic = args[0], args[1]
    content = " ".join(args[2:])
    result = save_area(area, topic, content)
    print(f"Saved to [{area}] topic [{topic}].")


def cmd_save_episode(args):
    """Save session episode: save-episode <chat_id> <chat_name> <summary>"""
    if len(args) < 3:
        print("Usage: save-episode <chat_id> <chat_name> <summary>")
        return
    chat_id, chat_name = args[0], args[1]
    summary = " ".join(args[2:])
    result = save_episode(chat_id, chat_name, summary)
    print(f"Session saved [{chat_name}].")


def cmd_search(args):
    """
    Search the brain.

    Usage:
      search <query>                  # advanced mode (default)
      search <query> --agentic        # agentic mode (most thorough)
      search <query> --hybrid         # hybrid mode (semantic + keyword)
      search <query> --naive          # naive mode (fastest)
      search <query> <collection>     # scope to a specific collection
      search <query> <collection> --agentic

    Collections: identity, facts, area_tech, area_business, area_people,
                 area_personal, projects, episodes, decisions, ideas
    """
    if not args:
        print("Usage: search <query> [collection] [--naive|--hybrid|--agentic]")
        return

    valid_collections = [
        "identity", "secrets_vault", "area_tech", "area_business",
        "area_people", "area_personal", "projects", "facts",
        "episodes", "decisions", "ideas"
    ]

    # Parse mode flag
    mode = "advanced"
    clean_args = []
    for a in args:
        if a == "--agentic":
            mode = "agentic"
        elif a == "--hybrid":
            mode = "hybrid"
        elif a == "--naive":
            mode = "naive"
        else:
            clean_args.append(a)

    # Parse optional collection scope (last arg if it's a known collection)
    collection = None
    if clean_args and clean_args[-1] in valid_collections:
        collection = clean_args[-1]
        query = " ".join(clean_args[:-1])
    else:
        query = " ".join(clean_args)

    if not query:
        print("Please provide a search query.")
        return

    mode_label = {"advanced": "Advanced RAG", "hybrid": "Hybrid RAG",
                  "agentic": "Agentic RAG", "naive": "Naive"}[mode]
    scope_label = f" [{collection}]" if collection else " [all collections]"
    print(f"\n  Searching{scope_label} using {mode_label}...\n")

    results = brain_search(query, collection=collection, mode=mode)

    if results:
        print(f"  Found {len(results)} results:\n")
        for i, r in enumerate(results, 1):
            score = r.get("score", 0)
            content = r.get("content", "")[:200]
            coll = r.get("collection", "")
            src = r.get("source", "semantic")
            src_tag = f"|{src}" if src != "semantic" else ""
            print(f"  {i}. [{score:.3f}|{coll}{src_tag}] {content}")
            print()
    else:
        print("  No results found.")


def cmd_status(args):
    """Show brain status."""
    try:
        s = status()
        print(f"\n{'='*55}")
        print(f"  PERSISTENT MEMORY STATUS")
        print(f"{'='*55}")
        print(f"  Connection: OK")
        print(f"  Storage: healthy")
        print(f"  Search: healthy")
        print(f"  RAG Mode: {s.get('rag_mode', 'Advanced + Hybrid + Agentic')}")
        print(f"  Total indexed: {s['total_vectors']} memories")
        print(f"\n  Collections:")
        for coll, count in s.get("collections", {}).items():
            print(f"    {coll}: {count} records")
        print(f"{'='*55}")
    except Exception as e:
        print(f"Memory connection error. Server may be offline.")


def cmd_nudge(args):
    """Auto-nudge: extract important info from conversation content."""
    if len(args) < 3:
        print("Usage: nudge <chat_id> <chat_name> <content>")
        return
    chat_id, chat_name = args[0], args[1]
    content = " ".join(args[2:])

    saved = []

    # Detect credentials/secrets
    ips = re.findall(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', content)
    passwords = re.findall(r'[Pp]assword[:\s]+(\S+)', content)
    api_keys = re.findall(r'(sk-[a-zA-Z0-9]{20,}|ghp_[a-zA-Z0-9]{20,}|[a-f0-9]{32,})', content)

    if passwords:
        for pw in passwords:
            save_secret(f"password-{chat_name}-{datetime.now().strftime('%H%M')}", pw,
                        "password", chat_name, f"Auto-extracted from {chat_name}")
            saved.append("credential detected")

    if api_keys:
        for key in api_keys:
            save_secret(f"api-key-{chat_name}-{datetime.now().strftime('%H%M')}", key,
                        "api_key", chat_name, f"Auto-extracted from {chat_name}")
            saved.append("api key detected")

    if ips and passwords:
        for ip in ips:
            save_secret(f"server-ip-{chat_name}", ip, "server", chat_name,
                        f"Server from {chat_name}")
            saved.append("server info detected")

    # Detect decisions
    decision_patterns = [
        r"(?:decided|going with|chose|will use|switching to|picked)\s+(.+?)(?:\.|$)",
    ]
    for pattern in decision_patterns:
        matches = re.findall(pattern, content, re.IGNORECASE)
        for match in matches:
            if len(match) > 10:
                save_decision(match.strip(), f"From {chat_name}", source_chat=chat_name)
                saved.append("decision detected")

    # Detect preferences
    pref_patterns = [
        r"[Ii] (?:prefer|like|want|hate|don't like|always use|never use)\s+(.+?)(?:\.|$)",
    ]
    for pattern in pref_patterns:
        matches = re.findall(pattern, content, re.IGNORECASE)
        for match in matches:
            if len(match) > 5:
                save_to_identity("preferences", match.strip())
                saved.append("preference detected")

    # Detect people mentions
    people_patterns = [
        r"(?:my (?:friend|colleague|partner|boss|client|brother|sister|wife|husband))\s+(\w+)",
    ]
    for pattern in people_patterns:
        matches = re.findall(pattern, content, re.IGNORECASE)
        for match in matches:
            save_area("people", match, f"Mentioned in {chat_name}")
            saved.append("person detected")

    if saved:
        print(f"Auto-saved {len(saved)} items from conversation.")
    else:
        print(f"No new items detected.")


def cmd_save_recipe(args):
    """Save a recipe (file/config/script): save-recipe <name> <content> [--project PROJECT] [--type TYPE] [--tags TAGS]"""
    if len(args) < 2:
        print("Usage: save-recipe <name> <content> [--project PROJECT] [--type TYPE] [--tags TAGS]")
        return
    name = args[0]
    project = ""
    file_type = ""
    tags = ""
    content_parts = []
    i = 1
    while i < len(args):
        if args[i] == "--project" and i+1 < len(args):
            project = args[i+1]; i += 2
        elif args[i] == "--type" and i+1 < len(args):
            file_type = args[i+1]; i += 2
        elif args[i] == "--tags" and i+1 < len(args):
            tags = args[i+1]; i += 2
        else:
            content_parts.append(args[i]); i += 1
    content = " ".join(content_parts)
    record = {
        "user_id": "owner",
        "name": name,
        "project": project,
        "description": "",
        "content": content,
        "file_type": file_type,
        "tags": tags,
        "timestamp": int(time.time()),
        "chat_id": ""
    }
    result = save_record("recipes", record)
    if result:
        print(f"  SAVED recipe: {name}")
    else:
        print(f"  FAILED to save recipe: {name}")


def cmd_list_recipes(args):
    """List all recipes, optionally filtered by project: list-recipes [project]"""
    from brain_client import _get_token, POCKETBASE_URL
    project_filter = args[0] if args else None
    token = _get_token()
    headers = {"Authorization": token}
    if project_filter:
        filter_str = f"?filter=(project='{project_filter}')&perPage=100&sort=-timestamp"
    else:
        filter_str = "?perPage=100&sort=-timestamp"
    r = requests.get(f"{POCKETBASE_URL}/api/collections/recipes/records{filter_str}",
        headers=headers, timeout=10)
    data = r.json()
    items = data.get('items', [])
    if not items:
        print("  No recipes found.")
        return
    print(f"\n  {len(items)} recipes:")
    for item in items:
        proj = f" [{item.get('project','')}]" if item.get('project') else ""
        ftype = f" ({item.get('file_type','')})" if item.get('file_type') else ""
        print(f"  - {item['name']}{proj}{ftype}")
    print()


def cmd_get_recipe(args):
    """Get a specific recipe by name: get-recipe <name>"""
    if not args:
        print("Usage: get-recipe <name>")
        return
    from brain_client import _get_token, POCKETBASE_URL
    name = args[0]
    token = _get_token()
    headers = {"Authorization": token}
    r = requests.get(f"{POCKETBASE_URL}/api/collections/recipes/records?filter=(name='{name}')&perPage=1",
        headers=headers, timeout=10)
    items = r.json().get('items', [])
    if not items:
        print(f"  Recipe '{name}' not found.")
        return
    item = items[0]
    print(f"\n  Name: {item['name']}")
    if item.get('project'):
        print(f"  Project: {item['project']}")
    if item.get('file_type'):
        print(f"  Type: {item['file_type']}")
    if item.get('tags'):
        print(f"  Tags: {item['tags']}")
    print(f"\n  Content:")
    print(item['content'])
    print()


# --- Main ---

COMMANDS = {
    "save": cmd_save,
    "save-full": cmd_save_full,
    "load": cmd_load,
    "save-brain": cmd_save_brain,
    "load-brain": cmd_load_brain,
    "save-secret": cmd_save_secret,
    "load-secrets": cmd_load_secrets,
    "save-fact": cmd_save_fact,
    "save-decision": cmd_save_decision,
    "save-idea": cmd_save_idea,
    "save-area": cmd_save_area,
    "save-episode": cmd_save_episode,
    "search": cmd_search,
    "status": cmd_status,
    "nudge": cmd_nudge,
    "save-recipe": cmd_save_recipe,
    "list-recipes": cmd_list_recipes,
    "get-recipe": cmd_get_recipe,
}

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Available commands:", ", ".join(COMMANDS.keys()))
        print("\nSearch modes: --naive | --hybrid | --agentic (default: advanced)")
        sys.exit(0)

    cmd = sys.argv[1]
    args = sys.argv[2:]

    if cmd in COMMANDS:
        COMMANDS[cmd](args)
    else:
        print(f"Unknown command: {cmd}")
        print("Available:", ", ".join(COMMANDS.keys()))
        sys.exit(1)
