#!/usr/bin/env sh
# modelstat — one-liner installer.
#
# Served at https://install.modelstat.ai — apps/api/src/index.ts maps
# that hostname to this file.
#
# Usage:
#   curl -fsSL https://install.modelstat.ai | sh
#
# What it does:
#   1. Detects your OS/arch and a suitable Node package manager
#      (pnpm → bun → npm, in that order).
#   2. Installs modelstat globally via that manager.
#   3. Runs `modelstat connect` to pair the device and install a
#      launchd (macOS) / systemd (Linux) user service.
#
# Every step prints what it's about to do BEFORE doing it. Nothing
# runs with sudo. Cancel any time with Ctrl-C.

set -eu

# ─── colours ────────────────────────────────────────────────────────
if [ -t 1 ] && [ "${TERM:-dumb}" != "dumb" ] && [ "${NO_COLOR:-}" = "" ]; then
  BRAND='\033[38;2;120;205;180m' # oklch(0.75 0.18 160) approx
  BOLD='\033[1m'; DIM='\033[2m'; RED='\033[31m'; RESET='\033[0m'
else
  BRAND=''; BOLD=''; DIM=''; RED=''; RESET=''
fi

say() { printf "%b\n" "$*"; }
step() { printf "\n%b▸ %b%s%b\n" "$BRAND" "$BOLD" "$1" "$RESET"; }
ok()   { printf "%b✓%b %s\n" "$BRAND" "$RESET" "$1"; }
fail() { printf "%b✗ %s%b\n" "$RED" "$1" "$RESET" >&2; }

banner() {
  say ""
  say "${BRAND}${BOLD}  modelstat installer${RESET}"
  say "${DIM}  https://modelstat.ai${RESET}"
  say ""
}

die() {
  fail "$1"
  say ""
  say "${DIM}If you need help: https://modelstat.ai/install${RESET}"
  exit 1
}

# ─── detect OS ──────────────────────────────────────────────────────
uname_s="$(uname -s 2>/dev/null || echo unknown)"
case "$uname_s" in
  Darwin) OS=macos ;;
  Linux)  OS=linux ;;
  *)      die "modelstat only supports macOS and Linux today (saw: $uname_s)." ;;
esac

uname_m="$(uname -m 2>/dev/null || echo unknown)"
case "$uname_m" in
  x86_64|amd64) ARCH=x86_64 ;;
  arm64|aarch64) ARCH=arm64 ;;
  *) die "Unsupported CPU architecture: $uname_m." ;;
esac

# ─── detect a package manager ───────────────────────────────────────
pick_pm() {
  if command -v pnpm >/dev/null 2>&1; then echo pnpm; return 0; fi
  if command -v bun  >/dev/null 2>&1; then echo bun;  return 0; fi
  if command -v npm  >/dev/null 2>&1; then echo npm;  return 0; fi
  return 1
}

install_cmd() {
  case "$1" in
    pnpm) echo "pnpm add -g modelstat" ;;
    bun)  echo "bun add -g modelstat"  ;;
    npm)  echo "npm install -g modelstat" ;;
  esac
}

# ─── main ────────────────────────────────────────────────────────────
banner
say "  ${DIM}detected: $OS / $ARCH${RESET}"

if command -v modelstat >/dev/null 2>&1; then
  step "modelstat is already installed"
  modelstat --version 2>/dev/null || true
  say "  ${DIM}skipping install — running \`modelstat connect\` next.${RESET}"
else
  PM="$(pick_pm || true)"
  if [ -z "${PM:-}" ]; then
    say ""
    fail "No Node.js package manager found (looked for pnpm, bun, npm)."
    say ""
    say "  Install Node 20+ from ${BOLD}https://nodejs.org${RESET} and try again,"
    say "  or install directly:"
    say "    ${DIM}npm install -g modelstat && modelstat connect${RESET}"
    exit 1
  fi

  step "Installing modelstat with $PM"
  cmd="$(install_cmd "$PM")"
  say "  ${DIM}→ $cmd${RESET}"
  # Run the install. Do not sudo — if this fails with EACCES the user
  # needs to fix their global prefix; we surface that clearly below.
  if ! $cmd; then
    say ""
    fail "Install failed."
    say ""
    say "  Most common cause: your global $PM prefix isn't writable."
    say "  Do NOT re-run with sudo. Instead:"
    say "    ${DIM}https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally${RESET}"
    exit 1
  fi
  ok "installed"
fi

# ─── optional: build the menu-bar tray on macOS ────────────────────
# Only macOS ships a tray (Linux desktops vary too much; systemd-only
# there is the spec). If Swift is on PATH (Xcode command-line tools
# count), build the Swift Package we ship inside the global install
# and drop the .app into ~/Applications. `modelstat connect` then
# picks it up automatically via bundledTrayAppPath().
if [ "$OS" = "macos" ]; then
  step "Menu-bar tray"
  if ! command -v swift >/dev/null 2>&1; then
    say "  ${DIM}Swift toolchain not found — skipping tray build.${RESET}"
    say "  ${DIM}Install Xcode command-line tools and re-run to get the menu-bar icon:${RESET}"
    say "  ${DIM}  xcode-select --install${RESET}"
  else
    # Resolve the installed modelstat so we can find the Swift
    # source shipped alongside it. Each pkg manager has its own prefix;
    # rely on `modelstat paths --json` as the common denominator.
    pkg_root="$(modelstat paths --json 2>/dev/null | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{const j=JSON.parse(s);const p=require("path");const m=require("module");const resolved=m.findPnpApi?null:null;process.stdout.write(require("path").resolve(require.resolve("modelstat/package.json"),".."));}catch(e){process.exit(1);}}' 2>/dev/null || true)"
    tray_src=""
    if [ -n "${pkg_root:-}" ] && [ -d "$pkg_root/vendor/tray-mac" ]; then
      tray_src="$pkg_root/vendor/tray-mac"
    elif [ -d "./apps/tray-mac" ]; then
      # Local dev: you're running install.sh from the repo root.
      tray_src="$(pwd)/apps/tray-mac"
    fi
    if [ -z "$tray_src" ]; then
      say "  ${DIM}Tray sources not found in the installed package — skipping.${RESET}"
    else
      say "  ${DIM}→ building ModelstatTray.app from $tray_src${RESET}"
      ( cd "$tray_src" && ./build-app.sh >/dev/null 2>&1 ) || {
        say "  ${DIM}tray build failed — continuing without a menu-bar icon.${RESET}"
      }
      if [ -d "$tray_src/build/ModelstatTray.app" ]; then
        mkdir -p "$HOME/Applications"
        rm -rf "$HOME/Applications/ModelstatTray.app"
        cp -R "$tray_src/build/ModelstatTray.app" "$HOME/Applications/ModelstatTray.app"
        ok "menu-bar icon installed at ~/Applications/ModelstatTray.app"
      fi
    fi
  fi
fi

step "Pairing this device"
say "  ${DIM}about to run \`modelstat connect\` — it will open your browser${RESET}"
say "  ${DIM}for a one-click approval, then install a background service.${RESET}"
say ""
# The `connect` command prints its own banner with URL + code and
# blocks until the browser approval returns (or times out). It exits 0
# on success, 1 on failure — either way we pass the status up.
modelstat connect

say ""
ok "modelstat is running. Dashboard: ${BRAND}https://modelstat.ai/dashboard${RESET}"
say "  ${DIM}Live numbers now: \`modelstat stats\`   ·   Pipeline queue: \`modelstat jobs\`${RESET}"
say "  ${DIM}Stop any time:    \`modelstat stop\`    ·   Service state:  \`modelstat status\`${RESET}"
