#!/usr/bin/env bash
# Keanu installer bootstrap — https://www.heykeanu.app/install.sh
#
#   curl -fsSL https://www.heykeanu.app/install.sh | bash
#
# Signs you in with the email you used at checkout, downloads the Keanu release
# for this Mac, verifies it, and hands off to the installer inside it. Safe to
# re-run. Everything is installed under ~/.keanu; nothing else on the system is
# touched except ~/Library/LaunchAgents, ~/.claude, and /usr/local/bin/keanu.
#
# Options (append after `bash -s --`):
#   --from <tarball>   install a local release tarball; no sign-in, no download
#   --version <v>      request a specific version instead of latest
#   any other flags    passed through to the installer (e.g. --skip-logins)
#
# Environment:
#   KEANU_API   licensing API base (default https://api.heykeanu.app)
#   KEANU_HOME  install root (default ~/.keanu)

set -euo pipefail

KEANU_API="${KEANU_API:-https://ljfjlmlw8g.execute-api.us-east-1.amazonaws.com/prod}"
KEANU_HOME="${KEANU_HOME:-$HOME/.keanu}"
DATA="${KEANU_DATA:-$KEANU_HOME/data}"
INSTALL_JSON="$DATA/routing/install.json"
FROM="" WANT_VERSION="latest" PASS=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --from) FROM="$2"; shift ;;
    --version) WANT_VERSION="$2"; shift ;;
    *) PASS+=("$1") ;;
  esac
  shift
done

say()  { printf '%s\n' "$*"; }
die()  { printf 'keanu install: %s\n' "$*" >&2; exit 1; }
ask()  { local v; if [[ -t 0 ]]; then read -r -p "$1" v; else read -r -p "$1" v < /dev/tty; fi; printf '%s' "$v"; }
# Flat-JSON field extractor for our own API responses (no jq on a fresh Mac).
jget() { printf '%s' "$1" | sed -n 's/.*"'"$2"'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1; }

[[ "$(uname -s)" == "Darwin" ]] || die "Keanu runs on macOS only."
ARCH="$(uname -m)"
case "$ARCH" in arm64) ARCH=arm64 ;; x86_64) ARCH=x64 ;; *) die "unsupported CPU: $ARCH" ;; esac
command -v curl >/dev/null || die "curl is required"

say ""
say "Keanu installer"
say "  install root: $KEANU_HOME"
mkdir -p "$KEANU_HOME/app" "$DATA/routing"

TMP="$(mktemp -d "${TMPDIR:-/tmp}/keanu-install.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT
TGZ="$TMP/keanu.tgz"
VERIFY_JSON=""

if [[ -n "$FROM" ]]; then
  [[ -f "$FROM" ]] || die "no such file: $FROM"
  cp "$FROM" "$TGZ"
  say "  source: $FROM"
else
  # ── Sign in with the purchase email ──────────────────────────────────────
  TOKEN=""
  if [[ -f "$INSTALL_JSON" ]]; then TOKEN="$(jget "$(cat "$INSTALL_JSON")" token)"; fi
  if [[ -n "$TOKEN" ]]; then
    say "  using the existing sign-in in $INSTALL_JSON"
  else
    say ""
    EMAIL="$(ask "Email used at checkout: ")"
    [[ "$EMAIL" == *@* ]] || die "that does not look like an email address"
    curl -fsS -m 20 -X POST "$KEANU_API/auth/magic-link" -H 'content-type: application/json' \
      -d "{\"email\":\"$EMAIL\"}" >/dev/null || die "could not reach $KEANU_API — check your connection and try again"
    say "  If that email has a Keanu subscription, a 6-digit code is on its way (check spam)."
    CODE="$(ask "6-digit code: ")"
    VERIFY_JSON="$(curl -sS -m 20 -X POST "$KEANU_API/auth/verify" -H 'content-type: application/json' \
      -d "{\"email\":\"$EMAIL\",\"code\":\"$CODE\"}")"
    TOKEN="$(jget "$VERIFY_JSON" token)"
    [[ -n "$TOKEN" ]] || die "sign-in failed: $(jget "$VERIFY_JSON" error)"
    say "  signed in · $(jget "$VERIFY_JSON" tier) · $(jget "$VERIFY_JSON" max_projects) project(s)"
    # Stash token + email now; the installer's JSON helpers will tidy this file.
    printf '{ "email": "%s", "token": "%s", "api_base": "%s" }\n' "$EMAIL" "$TOKEN" "$KEANU_API" > "$INSTALL_JSON"
  fi

  # ── Resolve and download the release ─────────────────────────────────────
  META="$(curl -sS -m 20 "$KEANU_API/release/$WANT_VERSION?arch=$ARCH" -H "authorization: Bearer $TOKEN")"
  VERSION="$(jget "$META" version)"; URL="$(jget "$META" url)"; SHA="$(jget "$META" sha256)"
  [[ -n "$VERSION" && -n "$URL" ]] || die "could not get a release: $(jget "$META" error)"
  say "  downloading Keanu $VERSION for $ARCH..."
  curl -fSL --progress-bar -o "$TGZ" "$URL" || die "download failed"
  if [[ -n "$SHA" ]]; then
    [[ "$(shasum -a 256 "$TGZ" | awk '{print $1}')" == "$SHA" ]] || die "checksum mismatch; refusing to install"
    say "  checksum ok"
  fi
fi

# ── Extract into a versioned directory ─────────────────────────────────────
VERSION="$(tar -xzOf "$TGZ" ./VERSION 2>/dev/null | head -1 || true)"
[[ -n "$VERSION" ]] || VERSION="$(tar -xzOf "$TGZ" VERSION 2>/dev/null | head -1 || true)"
[[ -n "$VERSION" ]] || die "tarball has no VERSION file"
DEST="$KEANU_HOME/app/$VERSION"
rm -rf "$DEST.partial"; mkdir -p "$DEST.partial"
tar -xzf "$TGZ" -C "$DEST.partial"
# Re-running over the same version replaces the folder the dashboard and scan
# agents run from. Stop them first: a dashboard left running in a deleted
# folder starts every session there, and every one fails (v1.43 run B). The
# installer starts them again at its last step.
if [[ -d "$DEST" && "$(cd "$KEANU_HOME/current" 2>/dev/null && pwd -P)" == "$(cd "$DEST" && pwd -P)" ]]; then
  for label in app.heykeanu.dashboard app.heykeanu.scan; do
    launchctl bootout "gui/$(id -u)/$label" >/dev/null 2>&1 || true
  done
  say "  stopped the running dashboard; the installer restarts it"
fi
# Sessions address data as <version>/data: link it before the swap, so there
# is no moment where a write lands in a real folder there instead.
[[ -d "$DATA" ]] && ln -sfn "$DATA" "$DEST.partial/data"
rm -rf "$DEST"; mv "$DEST.partial" "$DEST"
say "  installed files for $VERSION"

# ── Write the license from the sign-in response, if we have one ────────────
if [[ -n "$VERIFY_JSON" ]]; then
  printf '%s' "$VERIFY_JSON" | "$DEST/node/bin/node" -e '
    let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{const r=JSON.parse(s);
      if(r.license){require("fs").writeFileSync(process.argv[1],JSON.stringify(r.license,null,2)+"\n")}}catch{}})' \
    "$DATA/routing/license.json"
fi

# ── Hand off to the versioned installer (reads prompts from the terminal) ──
# Hand it the real terminal device (/dev/ttysNNN), not /dev/tty: /dev/tty is a
# cloning device that kqueue rejects on macOS, and the Claude Code installer
# (built on bun) crashes with "EINVAL kqueue" when that is its stdin. Under
# `curl | bash` stdin is the pipe, so the device comes from stderr or stdout.
chmod +x "$DEST/scripts/keanu-install.sh" "$DEST/scripts/keanu" 2>/dev/null || true
TTY=""
for fd in 0 2 1; do
  t="$(tty 0<&$fd 2>/dev/null)" && [[ "$t" == /dev/* && "$t" != /dev/tty && -c "$t" ]] && { TTY="$t"; break; }
done
if [[ -n "$TTY" ]]; then
  exec "$DEST/scripts/keanu-install.sh" --fresh ${PASS[@]+"${PASS[@]}"} < "$TTY"
elif ( : < /dev/tty ) 2>/dev/null; then
  exec "$DEST/scripts/keanu-install.sh" --fresh ${PASS[@]+"${PASS[@]}"} < /dev/tty
else
  exec "$DEST/scripts/keanu-install.sh" --fresh ${PASS[@]+"${PASS[@]}"}
fi
