#!/bin/bash
set -euo pipefail

# Kimi Stop hook — checks patchcord inbox after each turn.
# Installed automatically by `npx patchcord` when Kimi CLI is detected.
#
# Resolves per-project .kimi-code/mcp.json only (walks up from cwd).
# No global fallback — a Kimi outside a patchcord worktree is not that agent.
#
# CRITICAL: Kimi v1.44.0 ONLY acts on Stop hooks when they BLOCK (exit code 2).
# stdout is silently discarded. stderr becomes the "reason" that triggers a new turn.

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

HOOK_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
if [ -f "$HOOK_DIR/lib/runtime-dir.sh" ]; then
  # shellcheck source=lib/runtime-dir.sh
  . "$HOOK_DIR/lib/runtime-dir.sh"
elif [ -f "$HOOK_DIR/runtime-dir.sh" ]; then
  . "$HOOK_DIR/runtime-dir.sh"
fi

INPUT=$(cat)

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

# Resolve MCP config: PROJECT-scoped ONLY (walk up from cwd for .kimi-code/mcp.json).
# NO global ~/.kimi/mcp.json fallback — a Kimi launched outside a patchcord
# worktree is not that agent and must not be nagged. No MCP authed in the cwd
# tree => no inbox check. (This Stop hook is registered globally in
# ~/.kimi/config.toml, so the project-scoped token is the ONLY thing that should
# make it act.)
KIMI_MCP=""
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null || echo "")

if [ -n "$CWD" ]; then
  dir="$CWD"
  while [ "$dir" != "/" ]; do
    if [ -f "$dir/.kimi-code/mcp.json" ]; then
      KIMI_MCP="$dir/.kimi-code/mcp.json"
      break
    fi
    dir=$(dirname "$dir")
  done
fi

# No project-scoped .kimi-code/mcp.json in the cwd tree => not a patchcord agent here.
[ -z "$KIMI_MCP" ] && exit 0

TOKEN=""
URL=""

if [ -f "$KIMI_MCP" ]; then
  TOKEN=$(jq -r '.mcpServers.patchcord.headers.Authorization // empty' "$KIMI_MCP" 2>/dev/null | sed 's/^Bearer //i' || true)
  URL=$(jq -r '.mcpServers.patchcord.url // empty' "$KIMI_MCP" 2>/dev/null || true)
fi

[ -z "$URL" ] || [ -z "$TOKEN" ] && exit 0

# Normalize URL to base
BASE_URL=$(echo "$URL" | sed 's|/mcp$||; s|/mcp/bearer$||')

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

[ "$HTTP_CODE" != "200" ] && exit 0

COUNT=$(echo "$RESPONSE" | jq -r '.count // .pending_count // 0' 2>/dev/null || echo "0")

[ "$COUNT" -gt 0 ] || exit 0

# Deduplicate: only notify once every 30 seconds
RUNTIME_DIR=$(pc_runtime_dir 2>/dev/null || true)
[ -n "$RUNTIME_DIR" ] || exit 0
NOTIFY_LOCK="$RUNTIME_DIR/patchcord_kimi_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 30 ] && exit 0
fi

touch "$NOTIFY_LOCK"

# Exit 2 + stderr = Kimi starts a new turn with this as the user message.
# stdout is silently discarded by Kimi for Stop hooks.
printf '%s\n' "📬 Patchcord: You have ${COUNT} pending message(s). Call inbox() to read and reply." >&2
exit 2
