#!/usr/bin/env python3
"""
parse-ghostty-session — read a raw Ghostty/script terminal log, summarize it
with `claude -p`, save to vault, and update companion files.

Usage: parse-ghostty-session <logfile.log>

Install: copy to ~/.local/bin/parse-ghostty-session and chmod +x

Input:  ~/.logs/terminal/YYYY-MM/DATETIME-ghostty.log  (from `script -q -f`)
Output: <vault_dir>/YYYY-MM/DATETIME-ghostty-<cwd-slug>.md
        + companion file update via update-session-docs

Config: reads vault_dir from ~/.devme/config.json (default: ~/Documents/sessions)
"""

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


# ── Config ────────────────────────────────────────────────────────────────────

def _load_config() -> dict:
    defaults = {"vault_dir": str(Path.home() / "Documents" / "sessions")}
    cfg_path = Path.home() / ".devme" / "config.json"
    legacy_cfg_path = Path.home() / ".ash" / "config.json"
    if not cfg_path.exists() and legacy_cfg_path.exists():
        cfg_path = legacy_cfg_path
    if cfg_path.exists():
        try:
            loaded = json.loads(cfg_path.read_text())
            if "vault_dir" in loaded:
                defaults["vault_dir"] = loaded["vault_dir"]
        except Exception:
            pass
    return defaults

CFG        = _load_config()
VAULT_DIR  = Path(CFG["vault_dir"]).expanduser()
CLAUDE_BIN = Path.home() / ".local/bin/claude"
UPDATE_DOCS = Path.home() / ".local/bin/update-session-docs"

# ANSI escape sequence pattern
ANSI_ESC = re.compile(
    r"\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]"
)
# OSC 7 shell integration — cwd advertisement
OSC7 = re.compile(r"\x1b\]7;file://[^/]*(/.+?)[;\x07\\]")


def strip_ansi(text: str) -> str:
    return ANSI_ESC.sub("", text)


def detect_cwd(raw: str) -> str:
    matches = OSC7.findall(raw)
    return matches[-1] if matches else str(Path.home())


def clean_log(path: Path) -> tuple[str, str]:
    raw  = path.read_text(errors="replace")
    cwd  = detect_cwd(raw)
    clean = strip_ansi(raw)
    lines = [
        l for l in clean.splitlines()
        if not l.startswith("Script started") and not l.startswith("Script done")
    ]
    if len(lines) > 400:
        lines = (
            lines[:200]
            + ["", "[... middle of session omitted for length ...]", ""]
            + lines[-200:]
        )
    return "\n".join(lines), cwd


def build_prompt(log_text: str, cwd: str) -> str:
    project = Path(cwd).name if cwd != str(Path.home()) else "home"
    return f"""You are summarizing a terminal session log for the developer's personal archive.
The log is raw terminal output from a Ghostty window (captured via `script`).
Be specific and concrete — this is reference material the developer will search later.

Working directory: {cwd}
Project: {project}

Terminal log:
{log_text}

Write a session summary using exactly these sections (omit a section only if there is genuinely nothing to say):

## Key Points
- [3–7 concise bullets: what was being done, what commands were run, what was accomplished]

## Decisions & Reasoning
[Notable decisions, errors encountered and how they were resolved, approaches tried. Use bullets.]

## Instructionals & Code
[Reproduce any notable commands, scripts, config snippets, or outputs worth preserving. Use fenced code blocks.]

## Takeaway
[1–2 sentences, plain English. What was this session fundamentally about and what was the outcome?]"""


def already_archived(log_path: Path) -> bool:
    if not VAULT_DIR.exists():
        return False
    tag = hashlib.md5(str(log_path).encode()).hexdigest()[:8]
    return any(tag in p.name for p in VAULT_DIR.rglob("*.md"))


def main():
    if len(sys.argv) < 2:
        print("Usage: parse-ghostty-session <logfile.log>", file=sys.stderr)
        sys.exit(1)

    log_path = Path(sys.argv[1])
    if not log_path.exists():
        print(f"Log not found: {log_path}", file=sys.stderr)
        sys.exit(1)

    if not CLAUDE_BIN.exists():
        print(f"claude binary not found at {CLAUDE_BIN}", file=sys.stderr)
        sys.exit(1)

    if already_archived(log_path):
        print(f"Already archived — skipping: {log_path.name}")
        sys.exit(0)

    log_text, cwd = clean_log(log_path)
    if len(log_text.strip()) < 50:
        print("Log too short — skipping", file=sys.stderr)
        sys.exit(0)

    prompt = build_prompt(log_text, cwd)
    env    = os.environ.copy()
    env.pop("CLAUDECODE", None)

    try:
        result = subprocess.run(
            [str(CLAUDE_BIN), "-p", "--no-session-persistence"],
            input=prompt, capture_output=True, text=True, timeout=120, env=env,
        )
    except subprocess.TimeoutExpired:
        print("claude -p timed out after 120s", file=sys.stderr)
        sys.exit(1)

    if result.returncode != 0:
        print(f"claude -p failed (exit {result.returncode}):\n{result.stderr[:500]}", file=sys.stderr)
        sys.exit(1)

    summary = result.stdout.strip()
    if not summary:
        print("claude -p returned empty output — skipping", file=sys.stderr)
        sys.exit(1)

    ts = datetime.now()
    m  = re.search(r"(\d{4})-(\d{2})-(\d{2})-(\d{6})", log_path.stem)
    if m:
        try:
            ts = datetime.strptime("".join(m.groups()), "%Y%m%d%H%M%S").astimezone()
        except ValueError:
            pass

    project_slug = re.sub(r"[^\w\-]", "_", Path(cwd).name or "home")
    path_tag     = hashlib.md5(str(log_path).encode()).hexdigest()[:8]

    VAULT_DIR.mkdir(parents=True, exist_ok=True)
    month_dir = VAULT_DIR / ts.strftime("%Y-%m")
    month_dir.mkdir(exist_ok=True)

    filename    = f"{ts.strftime('%Y-%m-%d-%H%M%S')}-ghostty-{project_slug}-{path_tag}.md"
    output_path = month_dir / filename

    output = f"""# {project_slug} (ghostty)

| | |
|---|---|
| **Date** | {ts.strftime("%Y-%m-%d %H:%M")} |
| **Tool** | ghostty |
| **Project** | {cwd} |
| **Log** | `{log_path}` |

---

{summary}
"""
    output_path.write_text(output)
    print(f"Saved: {output_path}")

    if UPDATE_DOCS.exists():
        subprocess.Popen(
            [str(UPDATE_DOCS), "--summary", summary,
             "--cwd", cwd, "--tool", "ghostty", "--date", ts.isoformat()],
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
        )


if __name__ == "__main__":
    main()
