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

LOG=/tmp/tuple-trigger-debug.log
{
    printf '\n=== %s call-transcription-started fired (open-in-pi) ===\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 "open-in-pi: 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 "open-in-pi: 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

PID_FILE="${TRANSCRIPTION_DIR}/pi-sidekick.pid"
PROMPT_FILE="${TRANSCRIPTION_DIR}/pi-sidekick-prompt.md"
# 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:-}"
LAUNCHER_FILE="${TRANSCRIPTION_DIR}/launch-pi-sidekick.command"

if [ -f "${PID_FILE}" ] && kill -0 "$(cat "${PID_FILE}" 2>/dev/null)" 2>/dev/null; then
    echo "open-in-pi: Pi sidekick already running for ${TRANSCRIPTION_DIR}"
    exit 0
fi

# Ship the call-watcher extension into the transcription directory so Pi loads it
# automatically at startup — no /reload, no self-authoring. Pi auto-discovers
# `.pi/extensions/*.ts` from its working directory, which is this directory.
TRIGGER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
EXTENSION_SRC="${TRIGGER_DIR}/tuple-call-watch.ts"
EXTENSION_DIR="${TRANSCRIPTION_DIR}/.pi/extensions"
mkdir -p "${EXTENSION_DIR}"
if [ -f "${EXTENSION_SRC}" ]; then
    cp "${EXTENSION_SRC}" "${EXTENSION_DIR}/tuple-call-watch.ts"
    printf '{ "artifactsDir": "%s", "callId": "%s" }\n' "${TRANSCRIPTION_DIR}" "${CALL_ID}" \
        > "${EXTENSION_DIR}/tuple-call-watch.config.json"
else
    echo "open-in-pi: shipped extension not found at ${EXTENSION_SRC}; Pi will read transcript files directly" >&2
fi

{
    cat <<'PROMPT'
You are a real-time companion on a live Tuple pair-programming call, running inside Pi. Your working directory is the current Tuple transcription directory opened by this trigger.

PROMPT
    printf 'The trigger fired for:\n\n'
    printf -- '- Transcription directory: %s\n' "${TRANSCRIPTION_DIR}"
    printf -- '- Session directory name: %s\n' "${SESSION_DIR}"
    printf -- '- Inferred call id: %s\n' "${CALL_ID}"
    cat <<'PROMPT'

Other call participants do not see your output; you interact only with the user at this terminal.

## You are an active listener

A watcher extension (`tuple-call-watch`) shipped with this trigger and loaded automatically when you started — nothing to set up, no `/reload`. It tails the live transcript and, whenever the talkers pause, sends you a `tuple-call-watch` message beginning "New on the call:" with the lines that just landed (speaker names already resolved). Each of those messages is delivered as its own turn, so you are reading the conversation as it happens, batch by batch — not waiting for the user to prompt you.

The watcher only ever feeds you a batch while you are idle, and it never stops for the whole session. So the user's own messages always take priority — when they talk to you, you answer them first — and the instant you finish, the next batch of call activity arrives and you keep listening. A user turn never pauses or ends the watch; batches keep coming until the call ends.

## Adaptive monitoring pace

The watcher starts in `balanced` mode and exposes a `tuple_call_watch_set_mode` tool you can use to change how quickly future transcript batches arrive. Use it sparingly: once when the call type becomes clear, and later only if the call shifts. If you call it, still finish the turn with the normal `·` summary or `👋` interjection for the current batch; do not mention the mode change unless the user asks.

- Use `realtime` for pair programming, debugging, design work, live coaching, or any call where timely interjections matter more than terminal quiet. In this mode the watcher polls the transcript much more frequently and flushes on shorter pauses.
- Use `balanced` for normal meetings, customer onboarding, interviews, and mixed discussion where short pauses are useful but constant updates would be noisy.
- Use `low_noise` for presentations, long monologues, status meetings, or any call where interruption would be distracting.

## Telling your two kinds of turn apart

Use the exact opening of each turn to know what it is:

- A turn whose message begins **"The call so far"** is the one-time backlog — read it for grounding and reply with no text. Do not comment on it retroactively.
- A turn whose message begins **"New on the call:"** is a transcript batch to evaluate (see below).
- **Anything else is the user typing to you directly** — a normal request. Answer it fully and normally; the wake-word caution below does not apply to it.

## Responding to a "New on the call:" batch

You are a sharp third pair on the call. For **every** batch, leave a single short line so the user can see you tracking the call live — never an empty turn. Match the line to what you heard:

- **Routine talk** (most batches): a one-line `· ` summary of what they just covered in this batch — a quick play-by-play in your own words so the user can follow the call at a glance without reading the transcript. A full sentence is good; capture the gist of what they're doing, deciding, or trying. For example: `· walking through extracting the session lookup into its own service before touching the controllers`, `· decided to fold the CI move to GitHub Actions into the same PR`, `· digging into why the webhook fires its retry twice`. Summarize in your own words — never restate lines verbatim — keep it to one line, and let it move with the conversation so consecutive summaries don't read the same.
- **Worth flagging** — a bug, mistake, or risk you can see and they apparently haven't; a decision or action item that is ambiguous, contested, or at risk of being lost; a factual correction that matters; a concrete answer to something they're visibly stuck on; or a line addressed to you directly ("Pi, ..."): lead with `👋 ` and say the useful thing in a sentence or two, like a knowledgeable colleague leaning in. For example: `👋 retrying without an idempotency key will double-charge — key off the Stripe event id`.

Keep it to one line for a `·` summary, a sentence or two when you raise a `👋`. No preamble; never open with "It sounds like", "Just to confirm", "I heard you say", or by restating their last line.

A line addresses you when "Pi" appears as a vocative ("Pi, ..." / "hey Pi"). Incidental uses like "the value of pi" or "a slice of pie" are not wakes, and a bare "Pi" with no request is not a wake — "Pi" is short and easily misheard, so when in doubt treat it as routine. A request may straddle two batches (the "Pi, ..." in one, the actual ask in the next); answer once the ask is complete.

**On `recording_stopped` or `recording_ended`**, give a concise checkpoint summary of the call so far: decisions, action items, and open threads. **On `call_ended`**, write a final summary (decisions, action items with owners, open threads) and end.

Open with a single short line confirming you are listening and caught up, then keep the call coming — one `·` summary line per batch, escalating to `👋` when it matters.
PROMPT
} > "${PROMPT_FILE}"

cat > "${LAUNCHER_FILE}" <<'SCRIPT'
#!/bin/zsh -li
printf '\e]0;Tuple Pi Sidekick\a'
clear
echo 'Starting Pi sidekick...'
echo

SCRIPT_DIR="${0:A:h}"
PID_FILE="${SCRIPT_DIR}/pi-sidekick.pid"
PROMPT_FILE="${SCRIPT_DIR}/pi-sidekick-prompt.md"

echo $$ > "${PID_FILE}"
cd "${SCRIPT_DIR}" || exit 1

if ! command -v pi >/dev/null 2>&1; then
    echo "Pi was not found on your interactive shell PATH."
    echo "Make sure 'pi' works in a new terminal, then run the trigger again."
    echo
    read '?Press return to close.'
    exit 127
fi

exec pi "$(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 [ "${OPEN_IN_PI_DRY_RUN:-}" = "1" ]; then
    echo "open-in-pi: dry run generated ${LAUNCHER_FILE}"
    exit 0
fi

launch_in_terminal "${LAUNCHER_FILE}"
