#!/usr/bin/env python3
"""
memory_context_inject.py — SessionStart hook: RLM Semantic Memory Injection
=============================================================================
Fires at session start (AFTER sunaiva_session_inject.py) to inject
semantically-relevant memories from the RLM bloodstream pipeline:

  Sources:
    1. Titan Memory axioms (KNOWLEDGE_GRAPH/axioms/*.jsonl)
    2. Qdrant genesis_memories (sentence-transformers semantic search)
    3. PostgreSQL digestion_kg_entities (recent high-confidence entities)
    4. PostgreSQL bloodstream_knowledge (task-keyword search)
    5. KG entity file fallback (last 5 JSONL files)

  Output:
    - Writes E:\\genesis-system\\data\\context_state\\injected_context.md
    - Returns it as additionalContext for Claude Code session startup

Architecture:
  This hook is a thin wrapper around core/session_context_injector.py.
  It runs the injector (which handles all DB calls and formatting),
  then reads the output file and returns it via the hook protocol.

  If the injector fails or is unavailable (missing deps), the hook
  silently returns {} so session startup is never blocked.

Position in hook chain (settings.json SessionStart):
  1. boot_context_inject.py        — WAR ROOM / boot context
  2. capability_audit.py           — capability manifest
  3. session_sync.py               — session state sync
  4. session_recovery_start.py     — handoff / recovery context
  5. sunaiva_session_inject.py     — Sunaiva vault entities (Grov-style)
  6. memory_context_inject.py      — THIS FILE: RLM semantic memories

Author: Genesis Systems Builder
Created: 2026-02-23
"""

from __future__ import annotations

import json
import os
import subprocess
import sys
from pathlib import Path

# ── Paths ─────────────────────────────────────────────────────────────────────
GENESIS_ROOT = Path("/mnt/e/genesis-system")
INJECTOR_SCRIPT = GENESIS_ROOT / "core" / "session_context_injector.py"
OUTPUT_FILE = GENESIS_ROOT / "data" / "context_state" / "injected_context.md"
MANIFEST_FILE = GENESIS_ROOT / "data" / "context_state" / "injected_context_manifest.json"

# Max chars to inject (don't overwhelm Claude's context on startup)
MAX_CONTEXT_CHARS = 6000

# Default task signal if no hook input provided
DEFAULT_TASK = "Genesis session start — operational memory"


def run_injector(task: str) -> bool:
    """Run session_context_injector.py as a subprocess. Returns True if succeeded."""
    try:
        result = subprocess.run(
            [
                sys.executable,
                str(INJECTOR_SCRIPT),
                "--task", task,
                "--top-k", "15",
                "--pg-hours", "48",
            ],
            capture_output=True,
            text=True,
            timeout=15,  # Max 15s — session startup must be fast
            cwd=str(GENESIS_ROOT),
            env={**os.environ, "PYTHONPATH": str(GENESIS_ROOT)},
        )
        return result.returncode == 0
    except subprocess.TimeoutExpired:
        # Injector took too long — session startup takes priority
        return False
    except Exception:
        return False


def read_injected_context() -> str | None:
    """Read the generated injected_context.md file."""
    try:
        if not OUTPUT_FILE.exists():
            return None
        content = OUTPUT_FILE.read_text(encoding="utf-8")
        if not content.strip():
            return None
        # Truncate if too large
        if len(content) > MAX_CONTEXT_CHARS:
            content = content[:MAX_CONTEXT_CHARS]
            content += "\n\n*(... memory context truncated for session startup ...)*"
        return content
    except Exception:
        return None


def read_manifest() -> dict:
    """Read the stats manifest for logging."""
    try:
        if MANIFEST_FILE.exists():
            return json.loads(MANIFEST_FILE.read_text(encoding="utf-8"))
    except Exception:
        pass
    return {}


def main():
    # Read hook input (Claude Code sends JSON via stdin)
    try:
        hook_input = json.loads(sys.stdin.read())
    except Exception:
        hook_input = {}

    # Extract task from hook input if available
    # Claude Code may pass session metadata we can use as task signal
    task = hook_input.get("task") or hook_input.get("description") or DEFAULT_TASK

    # Run the injector
    success = run_injector(task)

    if not success:
        # Injector failed — don't block session startup
        print(json.dumps({}))
        return

    # Read the output
    context_md = read_injected_context()

    if not context_md:
        print(json.dumps({}))
        return

    # Read manifest for a compact summary header
    manifest = read_manifest()
    qdrant_count = manifest.get("qdrant_results", 0)
    pg_count = manifest.get("pg_recent", 0)
    bloodstream_count = manifest.get("bloodstream", 0)
    titan_count = manifest.get("titan", 0)
    total = qdrant_count + pg_count + bloodstream_count + titan_count

    if total == 0:
        # No memories retrieved — don't inject empty context
        print(json.dumps({}))
        return

    # Prepend a compact summary line
    summary_header = (
        f"<!-- RLM Memory: {total} memories injected "
        f"(Titan:{titan_count} Qdrant:{qdrant_count} "
        f"PG:{pg_count} Bloodstream:{bloodstream_count}) -->\n\n"
    )
    full_context = summary_header + context_md

    # Return via Claude Code hook protocol
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "SessionStart",
            "additionalContext": full_context,
        }
    }))


if __name__ == "__main__":
    main()
