#!/usr/bin/env python3
"""
Sub-skill Dispatcher — router log + context-aware delegation hint.

The router (sub-skills/router.md) picks a sub-skill based on the user's
request. This script does the bookkeeping:

  - `log` writes a JSONL record of which sub-skill was picked and why
  - `show` reads back recent entries (audit + cost accounting)
  - `should-delegate` returns exit 0 (yes) / 1 (no) based on context-budget
    state, so the router can decide whether to load inline or spawn a subagent

The log lives at `.claude/sub-skill-log.jsonl` (project-local). Every entry:

    {"ts":"2026-05-21T07:00:00Z","sub_skill":"grill","sr":"SR-...","reason":"..."}

Why this exists:
  Sub-skill files are the most expensive context consumers in the pipeline.
  Without a log, "did the router actually load grill or did the model just
  guess?" is unanswerable. The log gives auditability and lets us tune the
  router rules later.

Usage:
    sub_skill_dispatcher.py log --sub-skill grill --sr SR-2026-001 --reason "..."
    sub_skill_dispatcher.py show [--limit N]
    sub_skill_dispatcher.py should-delegate    # exit 0 if delegate recommended

Exit codes:
    0 — success (or "yes delegate")
    1 — "no, load inline" (only for should-delegate)
    2 — error
"""

from __future__ import annotations

import argparse
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path

# Resolve project root from the script's own location: when installed as
# scripts/docs/sub_skill_dispatcher.py the project root is two levels up.
_DEFAULT_ROOT = Path(__file__).resolve().parents[2] if len(Path(__file__).resolve().parents) >= 3 else Path(".").resolve()
ROOT = Path(os.environ.get("PROJECT_ROOT", _DEFAULT_ROOT)).resolve()
LOG_PATH = ROOT / ".claude" / "sub-skill-log.jsonl"

# Same conservative thresholds as context_budget_check.py
DELEGATE_THRESHOLD = 140_000  # ~75% — switch to subagent delegation


def _ensure_log_dir() -> None:
    LOG_PATH.parent.mkdir(parents=True, exist_ok=True)


def cmd_log(args: argparse.Namespace) -> int:
    _ensure_log_dir()
    entry = {
        "ts": datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z"),
        "sub_skill": args.sub_skill,
        "sr": args.sr or None,
        "reason": args.reason or "",
    }
    with LOG_PATH.open("a", encoding="utf-8") as f:
        f.write(json.dumps(entry) + "\n")
    return 0


def cmd_show(args: argparse.Namespace) -> int:
    if not LOG_PATH.exists():
        print("no sub-skill log yet", file=sys.stderr)
        return 0
    lines = LOG_PATH.read_text(encoding="utf-8").splitlines()
    if args.limit:
        lines = lines[-args.limit:]
    for line in lines:
        try:
            entry = json.loads(line)
            sr = entry.get("sr") or "-"
            reason = entry.get("reason") or ""
            print(f"{entry['ts']}  {entry['sub_skill']:<12}  {sr:<20}  {reason}")
        except json.JSONDecodeError:
            continue
    return 0


def cmd_should_delegate(args: argparse.Namespace) -> int:
    """Exit 0 if subagent delegation is recommended, 1 if loading inline is fine."""
    transcript = os.environ.get("TRANSCRIPT", "")
    if not transcript:
        return 1
    size = len(transcript)
    if size >= DELEGATE_THRESHOLD:
        pct = int(size / 200_000 * 100)
        print(f"DELEGATE: context at ~{pct}%, spawn a subagent for the sub-skill")
        return 0
    return 1


def main() -> int:
    p = argparse.ArgumentParser(description="Sub-skill router dispatcher and log.")
    sub = p.add_subparsers(dest="cmd", required=True)

    p_log = sub.add_parser("log", help="record a routing decision")
    p_log.add_argument("--sub-skill", required=True,
                       choices=["router", "grill", "to-prd", "to-issues", "tdd",
                                "diagnose", "prototype", "triage", "zoom-out"])
    p_log.add_argument("--sr", help="related SR-ID if any")
    p_log.add_argument("--reason", help="one-line reason for the decision")

    p_show = sub.add_parser("show", help="print recent routing decisions")
    p_show.add_argument("--limit", type=int, default=20)

    sub.add_parser("should-delegate",
                   help="exit 0 if context-budget recommends spawning a subagent")

    args = p.parse_args()

    if args.cmd == "log":
        return cmd_log(args)
    if args.cmd == "show":
        return cmd_show(args)
    if args.cmd == "should-delegate":
        return cmd_should_delegate(args)
    return 2


if __name__ == "__main__":
    sys.exit(main())
