#!/bin/sh
# Agent Notifier - one-line installer.
#
#   curl -fsSL https://notifier.aicrew.in/i | sh
#
# Installs notify.py, links this machine to your account by browser approval,
# and sends a notification to prove it works. No API key is pasted anywhere.
set -eu

SITE_URL="${AGENT_NOTIFIER_SITE_URL:-https://notifier.aicrew.in}"
API_BASE="$SITE_URL/api/v1"
BIN_DIR="${AGENT_NOTIFIER_BIN_DIR:-$HOME/bin}"
NOTIFY="$BIN_DIR/notify.py"

# Colour only when attached to a terminal; piped output stays plain.
if [ -t 1 ]; then
  B=$(printf '\033[1m'); DIM=$(printf '\033[2m'); R=$(printf '\033[0m')
  GREEN=$(printf '\033[32m'); RED=$(printf '\033[31m')
else
  B=''; DIM=''; R=''; GREEN=''; RED=''
fi

say()  { printf '%s\n' "$*"; }
fail() { printf '%s%s%s\n' "$RED" "$*" "$R" >&2; exit 1; }

need() {
  command -v "$1" >/dev/null 2>&1 || fail "Agent Notifier needs $1. Install it and re-run this command."
}
need curl
need python3

# --- 1. Install the CLI -----------------------------------------------------
say "${B}Installing notify.py${R}"
mkdir -p "$BIN_DIR"
curl -fsSL "$SITE_URL/notify.py" -o "$NOTIFY" || fail "Could not download $SITE_URL/notify.py"
chmod +x "$NOTIFY"
say "  ${GREEN}OK${R} $NOTIFY"

# --- 2. Ask for a device code ----------------------------------------------
# python3 is already a hard dependency, so it parses the JSON. Requiring jq as
# well would double the number of machines this cannot run on.
json_get() { python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get(sys.argv[1],""))' "$1"; }
json_obj() { python3 -c 'import json,sys; print(json.dumps({sys.argv[1]: sys.argv[2]}))' "$1" "$2"; }

DEVICE_NAME=$(hostname 2>/dev/null || echo 'this machine')
CODE_JSON=$(curl -fsS -X POST "$API_BASE/device/code" \
  -H 'Content-Type: application/json' \
  -d "$(json_obj device_name "$DEVICE_NAME")") \
  || fail "Could not reach $API_BASE. Check your connection."

DEVICE_CODE=$(printf '%s' "$CODE_JSON" | json_get device_code)
USER_CODE=$(printf '%s' "$CODE_JSON" | json_get user_code)
VERIFY_URL=$(printf '%s' "$CODE_JSON" | json_get verification_uri_complete)
INTERVAL=$(printf '%s' "$CODE_JSON" | json_get interval)
[ -n "$DEVICE_CODE" ] || fail "Unexpected response from $API_BASE/device/code"
[ -n "$INTERVAL" ] || INTERVAL=3

say ""
say "${B}Authorize this machine${R}"
say "  Open: ${B}$VERIFY_URL${R}"
say "  Code: ${B}$USER_CODE${R}"
say "  ${DIM}Waiting for approval... (Ctrl-C to cancel)${R}"

# Best-effort: open the browser when there is one. Failure is fine - the URL is
# printed above, which is what makes this work over SSH.
if [ -z "${AGENT_NOTIFIER_NO_BROWSER:-}" ]; then
  { command -v open >/dev/null 2>&1 && open "$VERIFY_URL" >/dev/null 2>&1; } ||
  { command -v xdg-open >/dev/null 2>&1 && xdg-open "$VERIFY_URL" >/dev/null 2>&1; } || true
fi

# --- 3. Poll until approved -------------------------------------------------
API_KEY=''
DEADLINE=$(( $(date +%s) + 600 ))
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
  sleep "$INTERVAL"
  TOKEN_JSON=$(curl -fsS -X POST "$API_BASE/device/token" \
    -H 'Content-Type: application/json' \
    -d "$(json_obj device_code "$DEVICE_CODE")") || continue
  STATUS=$(printf '%s' "$TOKEN_JSON" | json_get status)
  case "$STATUS" in
    approved) API_KEY=$(printf '%s' "$TOKEN_JSON" | json_get api_key); break ;;
    denied)   fail "That request was declined. Nothing was installed beyond notify.py." ;;
    expired)  fail "The code expired. Re-run: curl -fsSL $SITE_URL/i | sh" ;;
  esac
done
[ -n "$API_KEY" ] || fail "Timed out waiting for approval. Re-run: curl -fsSL $SITE_URL/i | sh"

# --- 4. Save the key --------------------------------------------------------
# Piped from a shell builtin, so the key never appears in the process list, and
# --save-config writes it to a 0600 file. No --project: notify.py detects one
# per git repo on every send, so projects appear by themselves.
if [ "$SITE_URL" = "https://notifier.aicrew.in" ]; then
  printf %s "$API_KEY" | "$NOTIFY" --save-config --api-key-stdin >/dev/null || fail "Could not save the API key."
else
  printf %s "$API_KEY" | "$NOTIFY" --save-config --api-key-stdin --base-url "$SITE_URL" >/dev/null || fail "Could not save the API key."
fi
say ""
say "  ${GREEN}OK${R} Key saved to ~/.config/agent-notifier/config.json"

# --- 5. Prove it works ------------------------------------------------------
if "$NOTIFY" "Agent Notifier is connected" >/dev/null 2>&1; then
  say "  ${GREEN}OK${R} Test notification sent - check your phone"
else
  say "  ${DIM}Key saved, but the test notification did not send. Try: $NOTIFY \"hello\"${R}"
fi

# --- 6. PATH ----------------------------------------------------------------
case ":$PATH:" in
  *":$BIN_DIR:"*) ;;
  *)
    say ""
    say "  ${DIM}$BIN_DIR is not on your PATH. Add this to your shell rc file:${R}"
    say "    export PATH=\"$BIN_DIR:\$PATH\""
    ;;
esac

# --- 7. Teach your agent to use it ------------------------------------------
# ~/AGENTS.md is the closest thing to a universal convention - Codex, opencode,
# and several other harnesses read it from the home directory by default. The
# HTML-comment markers let a re-run of this script recognise its own block
# instead of duplicating it. Failure here never aborts the install: the CLI
# itself is already working by this point.
say ""
say "${B}Teaching your agent${R}"
AGENTS_FILE="$HOME/AGENTS.md"

append_agent_guide() {
  if [ -s "$AGENTS_FILE" ]; then
    printf '\n' >> "$AGENTS_FILE" || return 1
  fi
  cat <<'AGENT_NOTIFIER_GUIDE_EOF' >> "$AGENTS_FILE" || return 1
<!-- BEGIN AGENT NOTIFIER NOTIFY.PY GUIDE -->
## Agent Notifier - keep the human updated (notify.py)

`~/bin/notify.py` pushes real-time updates to my phone and desktop. Use it two ways:

**Ask, don't wait silently.** When you need my input mid-task, use a blocking ask instead
of your built-in interactive question tool - I'm often away from the terminal, a push
reaches me and a terminal prompt does not.
- Yes/No or choices: `~/bin/notify.py --ask "Deploy to prod?" -c Deploy -c Hold`
- Typed answer: `~/bin/notify.py --ask-text "What should the branch be named?"`

**Report progress proactively, with proof.** Don't wait to be asked for status - send an
update at task start, every major milestone, each blocker, and completion, unprompted.
- Progress: `~/bin/notify.py "Migrating database" --progress 0.5`
- Proof: `~/bin/notify.py "Tests passing" --file-path ./logs/proof.png`
- Link: `~/bin/notify.py "PR ready" --url https://github.com/... --url-title "Open PR"`
- Blocked/urgent: `~/bin/notify.py "Blocked: need prod creds" --priority 1`

The project auto-detects from the git repo, never pass `--project`. Never echo the API
key. Never say a task is done without attaching proof. Run `~/bin/notify.py --help` for
the full flag list.
<!-- END AGENT NOTIFIER NOTIFY.PY GUIDE -->
AGENT_NOTIFIER_GUIDE_EOF
}

if [ -f "$AGENTS_FILE" ] && grep -qF "<!-- BEGIN AGENT NOTIFIER NOTIFY.PY GUIDE -->" "$AGENTS_FILE" 2>/dev/null; then
  say "  ${DIM}~/AGENTS.md already has the notify.py guide${R}"
elif append_agent_guide; then
  say "  ${GREEN}OK${R} Added a notify.py guide to ~/AGENTS.md"
else
  say "  ${DIM}Could not update ~/AGENTS.md - see $SITE_URL/setup to add it yourself${R}"
fi

say ""
say "${B}Done.${R} Notify yourself from anything:"
say "  ${DIM}$NOTIFY \"Build finished\"${R}"
say "  ${DIM}$NOTIFY --ask \"Deploy to prod?\" -c Deploy -c Hold${R}"
say "  ${DIM}Your coding agent already knows to use it - see ~/AGENTS.md${R}"
say ""
say "  Docs: $SITE_URL/setup"
