#!/usr/bin/env python3
"""Commit-subtask PreToolUse hook.

Reads a Claude Code PreToolUse payload from stdin. When the bash command is a
`git commit` with an inline message, checks the message for a Metrum-style
subtask reference (`#OZ10-18921`, `#WDV111`, etc.) and emits a non-blocking
advisory when missing.

Output shapes (matching view-conventions-check.py):
  - silent pass (not a commit, message already tagged, can't parse): exit 0,
    no stdout.
  - missing reference: exit 0 with JSON
    {"hookSpecificOutput": {"hookEventName": "PreToolUse",
                            "additionalContext": ...}}
    so the next turn sees the warning but the commit proceeds.

Crash safety: any unexpected exception is caught and reported to stderr with
exit 1 (non-blocking), so a hook bug never wedges the agent loop.
"""

from __future__ import annotations

import json
import re
import sys
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
STATE_FILE = PROJECT_ROOT / ".claude" / "current-subtask"

SUBTASK_RE = re.compile(r"#[A-Z]{2,5}\d+(?:-\d+)?")

HEREDOC_RE = re.compile(
    r"<<\s*['\"]?(\w+)['\"]?\s*\n(.*?)\n\s*\1\s*$",
    re.DOTALL | re.MULTILINE,
)
DOUBLE_QUOTED_M_RE = re.compile(r"-m\s+\"((?:[^\"\\]|\\.)*)\"", re.DOTALL)
SINGLE_QUOTED_M_RE = re.compile(r"-m\s+'((?:[^'\\]|\\.)*)'", re.DOTALL)


def extract_message(cmd: str) -> str | None:
    """Return the commit message body, or None if it can't be parsed."""
    heredoc = HEREDOC_RE.search(cmd)
    if heredoc:
        return heredoc.group(2)
    dq = DOUBLE_QUOTED_M_RE.search(cmd)
    if dq:
        return dq.group(1)
    sq = SINGLE_QUOTED_M_RE.search(cmd)
    if sq:
        return sq.group(1)
    return None


def main() -> int:
    try:
        payload = json.load(sys.stdin)
    except json.JSONDecodeError:
        return 0

    tool_name = payload.get("tool_name") or payload.get("toolName") or ""
    if tool_name and tool_name != "Bash":
        return 0

    tool_input = payload.get("tool_input") or payload.get("toolInput") or {}
    cmd = tool_input.get("command", "") if isinstance(tool_input, dict) else ""
    if not cmd:
        return 0

    if "git commit" not in cmd:
        return 0
    if "git merge" in cmd:
        return 0
    if "-m" not in cmd and "--message" not in cmd:
        return 0

    message = extract_message(cmd)
    if message is None:
        return 0

    if SUBTASK_RE.search(message):
        return 0

    suggestion = ""
    if STATE_FILE.exists():
        active = STATE_FILE.read_text().strip()
        if active:
            suggestion = f" Active subtask is `{active}` — consider prefixing with `#{active}`."

    advisory = {
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "additionalContext": (
                "Commit message has no Metrum subtask reference "
                "(expected format `#PREFIX-NNNN`)."
                + suggestion
            ),
        }
    }
    sys.stdout.write(json.dumps(advisory))
    return 0


if __name__ == "__main__":
    try:
        sys.exit(main())
    except Exception as exc:
        sys.stderr.write(f"commit-subtask-check.py crashed: {exc}\n")
        sys.exit(1)
