#!/bin/bash
set -euo pipefail

# Codex Stop hook — checks patchcord inbox after each turn.
# Installed automatically by `npx patchcord` when Codex is detected.

command -v jq >/dev/null 2>&1 || exit 0

# This script is COPIED to ~/.codex/patchcord-stop-hook.sh by the installer, so
# the shared guard is looked for both in the repo layout (scripts/lib/) and
# beside the installed copy, where `npx patchcord` drops it.
HOOK_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
if [ -f "$HOOK_DIR/lib/inbox-guard.sh" ]; then
  # shellcheck source=lib/inbox-guard.sh
  . "$HOOK_DIR/lib/inbox-guard.sh"
elif [ -f "$HOOK_DIR/patchcord-inbox-guard.sh" ]; then
  # shellcheck source=lib/inbox-guard.sh
  . "$HOOK_DIR/patchcord-inbox-guard.sh"
else
  pc_inbox_reason() { printf '%s patchcord message(s) waiting — call inbox() and reply.' "$1"; }
  pc_streak_ok() { return 0; }
  pc_state_path() { printf ''; }
  pc_streak_n() { printf '1'; }
fi

INPUT=$(cat)

PROJECT_CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null || true)
[ -z "$PROJECT_CWD" ] || [ "$PROJECT_CWD" = "null" ] && PROJECT_CWD="$PWD"

# Guard: stop_hook_active prevents infinite continuation loops
STOP_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null || echo "false")
if [ "$STOP_ACTIVE" = "true" ]; then
  exit 0
fi

# ── Resolve token + base URL from .codex/config.toml ─────────────────────────
TOKEN=""
URL=""
CODEX_TOML="$PROJECT_CWD/.codex/config.toml"

if [ -f "$CODEX_TOML" ]; then
  read -r URL TOKEN < <(python3 - "$CODEX_TOML" 2>/dev/null <<'PYEOF' || true
import re, sys
from urllib.parse import urlparse
content = open(sys.argv[1]).read()
url_m = re.search(r'\[mcp_servers\.patchcord[^\]]*\].*?url\s*=\s*"([^"]+)"', content, re.DOTALL)
auth_m = re.search(r'"Authorization"\s*=\s*"Bearer\s+([^"]+)"', content)
if url_m and auth_m:
    p = urlparse(url_m.group(1))
    base = f"{p.scheme}://{p.netloc}"
    print(base, auth_m.group(1).strip())
PYEOF
  ) || true
fi

if [ -z "$URL" ] || [ -z "$TOKEN" ]; then
  exit 0
fi

# ── Check pending count ───────────────────────────────────────────────────────
RESPONSE=$(curl -s -w $'\n%{http_code}' --max-time 5 \
  -H "Authorization: Bearer ${TOKEN}" \
  "${URL}/api/inbox?status=pending&limit=5&count_only=1" 2>/dev/null || printf '\n000')
HTTP_CODE=${RESPONSE##*$'\n'}
RESPONSE=${RESPONSE%$'\n'*}

if [ "$HTTP_CODE" = "401" ] || [ "$HTTP_CODE" = "403" ]; then
  jq -n '{"decision":"block","reason":"Patchcord token rejected (HTTP '"$HTTP_CODE"'). Check .codex/config.toml — re-run npx patchcord to fix."}'
  exit 0
fi

if [ "$HTTP_CODE" = "000" ]; then
  exit 0
fi

COUNT=$(echo "$RESPONSE" | jq -r '.count // .pending_count // 0' 2>/dev/null || echo "0")
case "$COUNT" in
  ''|*[!0-9]*) COUNT=0 ;;
esac

NAMESPACE=$(echo "$RESPONSE" | jq -r '.namespace_id // empty' 2>/dev/null || true)
AGENT_ID=$(echo "$RESPONSE" | jq -r '.agent_id // empty' 2>/dev/null || true)
STREAK_STATE=$(pc_state_path "patchcord_codex_streak" "$NAMESPACE" "$AGENT_ID" 2>/dev/null || echo "")

if [ "$COUNT" -eq 0 ]; then
  [ -n "$STREAK_STATE" ] && rm -f "$STREAK_STATE"
  exit 0
fi

RUNTIME_DIR=$(pc_runtime_dir 2>/dev/null || true)
[ -n "$RUNTIME_DIR" ] || exit 0
NOTIFY_LOCK="$RUNTIME_DIR/patchcord_codex_notify_lock"
if [ -f "$NOTIFY_LOCK" ]; then
  LOCK_MTIME=$(stat -c %Y "$NOTIFY_LOCK" 2>/dev/null || stat -f %m "$NOTIFY_LOCK" 2>/dev/null || echo "0")
  NOW=$(date +%s)
  [ $(( NOW - LOCK_MTIME )) -lt 5 ] && exit 0
fi

# Same-count/same-identity blocks give up after 3 — see lib/inbox-guard.sh.
if [ -n "$STREAK_STATE" ] \
   && ! pc_streak_ok "$STREAK_STATE" "${NAMESPACE}/${AGENT_ID}/${COUNT}" 3; then
  exit 0
fi

touch "$NOTIFY_LOCK"
# See check-inbox.sh: quiet on the first nudge, explain only once a repeat has
# proved inbox() did not clear it.
NUDGE_STREAK=$(pc_streak_n "$STREAK_STATE" 2>/dev/null || echo 1)
REASON=$(pc_inbox_reason "$COUNT" "$NAMESPACE" "$AGENT_ID" "inbox()" "restart this Codex session" "$NUDGE_STREAK")
jq -n --arg reason "$REASON" '{"decision":"block","reason":$reason}'
