"""CLI tool for stop-hook — captures conversation turns into conversation_log.db.

Reads the transcript JSONL from Claude Code, finds new user+assistant turns
since last run, and appends them to conversation_log.db. The digestor handles the rest.

Input (stdin): JSON with session_id, transcript_path, stop_hook_active, last_assistant_message

Usage:
    echo '{"session_id":"abc","transcript_path":"/tmp/t.jsonl"}' | neo-cortex-stop-hook
    echo '...' | neo-cortex-stop-hook --data-dir /path/to/data
"""

from __future__ import annotations

import argparse
import json
import os
import sqlite3
import sys
import time

_debug_enabled = False
_debug_log_path: str | None = None


def _log(msg: str) -> None:
    """Diagnostic log — no-op unless --debug is active."""
    global _debug_log_path
    if not _debug_enabled:
        return
    line = f"[stop_hook] {msg}"
    print(line, file=sys.stderr)
    if _debug_log_path:
        try:
            with open(_debug_log_path, "a", encoding="utf-8") as f:
                f.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {line}\n")
        except OSError as exc:
            print(f"[stop_hook] WARN: cannot write log: {exc}", file=sys.stderr)
            _debug_log_path = None


def _read_mcp_env(var_name: str) -> str | None:
    """Read an env var from .mcp.json neo-cortex server config."""
    for candidate in [
        os.path.join(os.getcwd(), ".mcp.json"),
        os.path.expanduser("~/neo-ram/.mcp.json"),
    ]:
        if os.path.exists(candidate):
            try:
                with open(candidate) as f:
                    data = json.load(f)
                for server in data.get("mcpServers", {}).values():
                    env = server.get("env", {})
                    if var_name in env:
                        return env[var_name]
            except Exception:
                pass
    return None


def _discover_data_dir(explicit: str | None = None) -> str | None:
    """Find cortex data directory (args → env → .mcp.json → fallback paths)."""
    data_dir = explicit or os.environ.get("CORTEX_DATA_DIR") or _read_mcp_env("CORTEX_DATA_DIR")
    if data_dir:
        return data_dir
    for candidate in [
        os.path.join(os.getcwd(), ".neo", "cortex", "data"),
        os.path.expanduser("~/neo-ram"),
    ]:
        if os.path.isdir(os.path.join(candidate, "cortex_db")):
            return candidate
    return None


def _get_last_line(state_dir: str, session_id: str) -> int:
    """Get the last transcript line number we processed for this session."""
    os.makedirs(state_dir, exist_ok=True)
    state_file = os.path.join(state_dir, f"{session_id}.offset")
    try:
        with open(state_file) as f:
            return int(f.read().strip())
    except (FileNotFoundError, ValueError):
        return 0


def _set_last_line(state_dir: str, session_id: str, line_num: int) -> None:
    os.makedirs(state_dir, exist_ok=True)
    state_file = os.path.join(state_dir, f"{session_id}.offset")
    with open(state_file, "w") as f:
        f.write(str(line_num))


def _extract_text(content: str | list) -> str:
    """Extract text from message content (string or list of blocks)."""
    if isinstance(content, str):
        return content.strip()
    if isinstance(content, list):
        parts = []
        for block in content:
            if isinstance(block, dict) and block.get("type") == "text":
                t = block.get("text", "").strip()
                if t:
                    parts.append(t)
        return " ".join(parts)
    return ""


def main(argv: list[str] | None = None) -> None:
    parser = argparse.ArgumentParser(description="Cortex stop-hook — capture turns to conversation_log")
    parser.add_argument("--data-dir", help="Cortex data directory (has cortex_db/)")
    parser.add_argument("--debug", action="store_true", help="Enable verbose logging to stderr and log file")
    args = parser.parse_args(argv)

    global _debug_enabled, _debug_log_path
    if args.debug:
        _debug_enabled = True

    t0 = time.time()

    # Read hook input from stdin
    try:
        raw = sys.stdin.read()
        data = json.loads(raw)
    except Exception as e:
        _log(f"ERROR reading stdin: {e}")
        return

    session_id = data.get("session_id", "unknown")
    transcript_path = data.get("transcript_path", "")
    stop_hook_active = data.get("stop_hook_active", False)

    if stop_hook_active:
        _log(f"skip: stop_hook_active=true session={session_id[:12]}")
        return

    if not transcript_path or not os.path.exists(transcript_path):
        _log(f"skip: no transcript session={session_id[:12]}")
        return

    # Discover data dir
    data_dir = _discover_data_dir(args.data_dir)
    if not data_dir:
        _log("no data dir found — exiting")
        return

    cortex_db = os.path.join(data_dir, "cortex_db")
    db_path = os.path.join(cortex_db, "conversation_log.db")
    state_dir = os.path.join(cortex_db, "stop-hook-state")

    if args.debug:
        _debug_log_path = os.path.join(cortex_db, "stop-hook.log")
        os.makedirs(cortex_db, exist_ok=True)
        _log(f"debug log: {_debug_log_path}")
        _log(f"env: CORTEX_DATA_DIR={os.environ.get('CORTEX_DATA_DIR', '<unset>')}")
        _log(f"cwd={os.getcwd()}")

    _log(f"processing session={session_id[:12]} transcript={transcript_path}")

    # Read transcript from last offset
    offset = _get_last_line(state_dir, session_id)
    turns: list[dict] = []
    last_line = offset

    try:
        with open(transcript_path) as f:
            for i, line in enumerate(f):
                if i < offset:
                    continue
                last_line = i + 1
                try:
                    obj = json.loads(line)
                except json.JSONDecodeError:
                    continue

                typ = obj.get("type", "")
                if typ == "user":
                    msg = obj.get("message", {})
                    text = _extract_text(msg.get("content", ""))
                    if text and len(text) > 2:
                        turns.append({
                            "role": "user",
                            "content": text[:4000],
                            "timestamp": obj.get("timestamp", time.time()),
                        })
                elif typ == "assistant":
                    msg = obj.get("message", {})
                    text = _extract_text(msg.get("content", ""))
                    if text and len(text) > 5:
                        turns.append({
                            "role": "assistant",
                            "content": text[:4000],
                            "timestamp": obj.get("timestamp", time.time()),
                        })
    except Exception as e:
        _log(f"ERROR reading transcript: {e}")
        return

    if not turns:
        _set_last_line(state_dir, session_id, last_line)
        _log(f"no new turns session={session_id[:12]}")
        return

    # Write to conversation_log.db
    try:
        conn = sqlite3.connect(db_path)
        conn.execute("PRAGMA journal_mode=WAL")

        conn.execute("""
            CREATE TABLE IF NOT EXISTS conversation_log (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp REAL NOT NULL,
                session_id TEXT NOT NULL,
                role TEXT NOT NULL,
                content TEXT NOT NULL,
                event_type TEXT,
                model TEXT,
                metadata TEXT,
                digested INTEGER DEFAULT 0
            )
        """)

        inserted = 0
        for turn in turns:
            conn.execute(
                """INSERT INTO conversation_log
                   (timestamp, session_id, role, content, event_type, model, digested)
                   VALUES (?, ?, ?, ?, ?, ?, 0)""",
                (turn["timestamp"], session_id, turn["role"], turn["content"], "stop-hook", "opus"),
            )
            inserted += 1

        conn.commit()
        conn.close()
        _set_last_line(state_dir, session_id, last_line)
        _log(f"OK: session={session_id[:12]} inserted={inserted} turns, offset={offset}→{last_line}")

    except Exception as e:
        _log(f"ERROR writing DB: {e}")

    _log(f"done in {time.time() - t0:.2f}s")


if __name__ == "__main__":
    main()
