#!/usr/bin/env bash
set -euo pipefail

# ---------------------------------------------------------------------------
# Set your preferred terminal here, or leave empty to auto-detect.
# One of: ghostty | iterm | alacritty | terminal
# (Also overridable from the environment: PREFERRED_TERM=iterm)
# ---------------------------------------------------------------------------
PREFERRED_TERM="${PREFERRED_TERM:-}"

LOG=/tmp/tuple-trigger-debug.log
{
    printf '\n=== %s call-transcription-started fired (claude-pairing-coach) ===\n' "$(date -u +%FT%TZ)"
    printf 'cwd=%s pid=%s ppid=%s\n' "$(pwd)" "$$" "$PPID"
    printf 'argv: %s\n' "$*"
    printf 'env (filtered):\n'
    env | grep -E '^(HOME|USER|PATH|TUPLE_|CURRENT_USER_)' | sort
} >> "$LOG" 2>&1
trap 'printf "exit status=%s on line %s\n" "$?" "$LINENO" >> "$LOG"' EXIT
exec >>"$LOG" 2>&1

if [ -z "${TUPLE_TRIGGER_CALL_ARTIFACTS_DIRECTORY:-}" ]; then
    echo "claude-pairing-coach: TUPLE_TRIGGER_CALL_ARTIFACTS_DIRECTORY was not set" >&2
    exit 1
fi

TRANSCRIPTION_DIR="${TUPLE_TRIGGER_CALL_ARTIFACTS_DIRECTORY}"
if [ ! -d "${TRANSCRIPTION_DIR}" ]; then
    echo "claude-pairing-coach: transcription directory does not exist: ${TRANSCRIPTION_DIR}" >&2
    exit 1
fi

SESSION_DIR="$(basename "${TRANSCRIPTION_DIR}")"
PARENT_DIR="$(dirname "${TRANSCRIPTION_DIR}")"
PARENT_NAME="$(basename "${PARENT_DIR}")"
if [[ "${SESSION_DIR}" == *"@"* ]]; then
    CALL_ID="${SESSION_DIR##*@}"
elif [[ "${PARENT_NAME}" =~ ^[0-9A-Fa-f-]{8,}$ ]]; then
    CALL_ID="${PARENT_NAME}"
else
    CALL_ID="${SESSION_DIR}"
fi

# Infer the identity-file env from the artifacts path: staging recordings live
# under ~/.tuplestaging, production under ~/.tuple. No CLI probe needed.
case "${TRANSCRIPTION_DIR}" in
    *"/.tuplestaging/"*) IDENTITY_FILE="${HOME}/.tuplestaging/identity.md" ;;
    *) IDENTITY_FILE="${HOME}/.tuple/identity.md" ;;
esac

# PID dedup stable across transcription restarts: keyed on the call id (which
# survives stop/restart) and parked in the transcripts root, not the session
# dir (which is recreated on each restart).
PID_FILE="${PARENT_DIR}/.pairing-coach-${CALL_ID}.pid"
SYSTEM_PROMPT_FILE="${TRANSCRIPTION_DIR}/pairing-coach-system-prompt.md"
PROMPT_FILE="${TRANSCRIPTION_DIR}/pairing-coach-initial-prompt.md"
LAUNCHER_FILE="${TRANSCRIPTION_DIR}/launch-pairing-coach.command"
TRIGGER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
WATCHER_SRC="${TRIGGER_DIR}/tuple-call-watcher.py"
WATCHER_DST="${TRANSCRIPTION_DIR}/tuple-call-watcher.py"

# If a coach session is still alive (transcription was stopped and restarted),
# leave it be — its watcher already follows the restarted session via the
# `*@<call-id>/` glob.
if [ -f "${PID_FILE}" ] && kill -0 "$(cat "${PID_FILE}" 2>/dev/null)" 2>/dev/null; then
    echo "claude-pairing-coach: pairing coach already running for call ${CALL_ID}"
    exit 0
fi

# Ship the fixed, deterministic transcript watcher next to the live transcript
# files so the model runs it verbatim instead of authoring a poll loop each
# session (which is non-deterministic and silently emits nothing when it reaches
# for bash-isms under the zsh-launched Monitor).
if [ -f "${WATCHER_SRC}" ]; then
    cp "${WATCHER_SRC}" "${WATCHER_DST}"
    chmod 0755 "${WATCHER_DST}"
else
    echo "claude-pairing-coach: watcher not found at ${WATCHER_SRC}" >&2
    exit 1
fi

# Ship the best-effort desktop-notification helper next to the watcher so the
# coach can raise a popup without hand-escaping AppleScript (it passes text as
# arguments). Notifications are a bonus; the coach always keeps a terminal line,
# so a missing helper is non-fatal.
NOTIFY_SRC="${TRIGGER_DIR}/tuple-notify.sh"
NOTIFY_DST="${TRANSCRIPTION_DIR}/tuple-notify.sh"
if [ -f "${NOTIFY_SRC}" ]; then
    cp "${NOTIFY_SRC}" "${NOTIFY_DST}"
    chmod 0755 "${NOTIFY_DST}"
fi

# Build the appended system prompt: operational/framework rules first, then
# optional identity grounding so the model knows your user's name and pairing
# tendencies. NEVER rm -rf the session dir — it holds live transcription files.
cp "${TRIGGER_DIR}/system-prompt.md" "${SYSTEM_PROMPT_FILE}"
if [ -f "${IDENTITY_FILE}" ]; then
    printf '\n---\n\n' >> "${SYSTEM_PROMPT_FILE}"
    cat "${IDENTITY_FILE}" >> "${SYSTEM_PROMPT_FILE}"
fi

cat > "${PROMPT_FILE}.tmpl" <<'PROMPT'
You are the pairing coach on a live Tuple pair-programming call. Transcription just started (or resumed) on this call. The active session for *this* call is `./__SESSIONDIR__/`, holding `events.jsonl` and `transcriptions.jsonl`; your working directory is the transcripts root, which holds one directory per session (this call's are every dir matching `./*@__CALLID__/`).

Watch the live transcript for pairing anti-patterns — backseat driving, a quiet pair, a silent driver, no goal set, no swaps or breaks — and surface a one-line move your user can make to fix it (a terminal note plus a best-effort desktop notification, per your system prompt). Stay otherwise silent.

Follow the Setup steps in your appended system prompt. First, catch up on everything said before you joined by running the bundled watcher once via Bash:

    ./__SESSIONDIR__/tuple-call-watcher.py --catchup --offsets pairing-coach

Then return silently and wait for a wake signal.
PROMPT
# bash 3.2 (macOS default) mangles heredocs inside $()/`` so the prompt is
# written straight to a file, then placeholders are substituted with sed.
sed -e "s|__SESSIONDIR__|${SESSION_DIR}|g" -e "s|__CALLID__|${CALL_ID}|g" "${PROMPT_FILE}.tmpl" > "${PROMPT_FILE}"
rm -f "${PROMPT_FILE}.tmpl"

# The launcher self-locates via ${0:A:h} (the session dir it is written into) and
# derives every path from there, so nothing but the call-id is baked in. CALL_ID
# rides in through a short unquoted preamble — a plain assignment with no $$/$(...)
# to escape — and the quoted SCRIPT body then uses $$ and $(cat ...) verbatim.
cat > "${LAUNCHER_FILE}" <<EOF
#!/bin/zsh -li
CALL_ID='${CALL_ID}'
EOF
cat >> "${LAUNCHER_FILE}" <<'SCRIPT'
SHORT_ID="${CALL_ID:0:8}"
printf '\e]0;Pairing Coach %s\a' "${SHORT_ID}"
clear
echo 'Starting Pairing Coach…'
echo

SCRIPT_DIR="${0:A:h}"
SYSTEM_PROMPT_FILE="${SCRIPT_DIR}/pairing-coach-system-prompt.md"
PROMPT_FILE="${SCRIPT_DIR}/pairing-coach-initial-prompt.md"
# PID file lives in the transcripts root (the session dir's parent), keyed by
# call-id, so a mid-call transcription restart finds this session and skips
# relaunching even though the session dir itself is recreated.
PID_FILE="${SCRIPT_DIR}/../.pairing-coach-${CALL_ID}.pid"

echo $$ > "${PID_FILE}"
# cwd = the transcripts root (parent of this call's session dir) so the watcher
# path `./<session-dir>/...` and the retro `./*@<call-id>/` glob both resolve.
cd "${SCRIPT_DIR}/.." || exit 1

if ! command -v claude >/dev/null 2>&1; then
    echo "Claude Code was not found on your interactive shell PATH."
    echo "Make sure 'claude' works in a new terminal, then run the trigger again."
    echo
    read '?Press return to close.'
    exit 127
fi
if ! command -v python3 >/dev/null 2>&1; then
    echo "The Tuple watcher needs python3 (install Xcode Command Line Tools: xcode-select --install)."
    echo
    read '?Press return to close.'
    exit 127
fi

exec claude \
    --model opus \
    --effort low \
    --name "Tuple Pairing Coach" \
    --append-system-prompt-file "${SYSTEM_PROMPT_FILE}" \
    "$(cat "${PROMPT_FILE}")"
SCRIPT
chmod 0755 "${LAUNCHER_FILE}"

# --- launch_in_terminal: open the .command launcher in the user's terminal ---
# Uses LaunchServices (`open`) only — no direct binary exec and no AppleScript,
# so it triggers no macOS accessibility prompt and no stray empty windows.
# With PREFERRED_TERM empty, the launcher opens in your default handler for
# .command files (change it in Finder: right-click a .command > Open With >
# your terminal > Change All). Set PREFERRED_TERM to force one for this trigger.
# Ghostty, iTerm, and Terminal run an opened .command directly; Alacritty has no
# document handler, so it is launched with `open -na ... --args -e`.
launch_in_terminal() {
    local file="$1"
    case "${PREFERRED_TERM:-}" in
    "") open "$file" ;;
    ghostty) open -a "Ghostty" "$file" 2>/dev/null || open "$file" ;;
    iterm) open -a "iTerm" "$file" 2>/dev/null || open "$file" ;;
    terminal) open -a "Terminal" "$file" 2>/dev/null || open "$file" ;;
    alacritty) open -na "Alacritty" --args -e "$file" 2>/dev/null || open "$file" ;;
    *) echo "launch_in_terminal: unknown PREFERRED_TERM='${PREFERRED_TERM}'; using default handler" >&2; open "$file" ;;
    esac
}

if [ "${CLAUDE_PAIRING_COACH_DRY_RUN:-}" = "1" ]; then
    echo "claude-pairing-coach: dry run generated ${LAUNCHER_FILE}"
    exit 0
fi

launch_in_terminal "${LAUNCHER_FILE}"
