#!/usr/bin/env bash
#
# detesting.ai CLI installer
#
#   curl -fsSL https://robot.detesting.ai/cli/install.sh | bash
#
# With options (note the `-s --`, which is how flags survive a curl pipe):
#   curl -fsSL https://robot.detesting.ai/cli/install.sh | bash -s -- \
#     --project my-project \
#     --api-url https://robot.detesting.ai/api
#
# The tarball is served next to this script rather than published to npm, so
# installing is a download plus a local npm install — no registry account.
#
# Browser tests need Chromium (~300 MB). That is NOT installed here: most
# people install this CLI to run API tests, and a 300 MB surprise inside a
# curl pipe is hostile. Run `dt browser install` when you need it.

set -euo pipefail

BOLD='\033[1m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
DIM='\033[0;90m'
RESET='\033[0m'

BASE_URL="${DT_CLI_BASE_URL:-https://robot.detesting.ai/cli}"
MIN_NODE_VERSION=20

API_URL=""
PROJECT=""
VERSION="latest"
SKIP_CHECKSUM="false"
WITH_BROWSER="false"
UNINSTALL="false"

say()  { echo -e "${GREEN}✓${RESET} $1"; }
warn() { echo -e "${YELLOW}!${RESET} $1"; }
fail() { echo -e "${RED}✖${RESET} $1" >&2; exit 1; }
step() { echo -e "${DIM}→${RESET} $1"; }

usage() {
  cat <<'EOF'
detesting.ai CLI installer

  --project  <name>    Project to bind after installing
  --api-url  <url>     API to point at (default https://robot.detesting.ai/api)
  --version  <ver>     Install a specific version instead of latest
  --with-browser       Also download Chromium for local browser tests (~300 MB)
  --skip-checksum      Do not verify the tarball checksum
  --uninstall          Remove the CLI
  --help               Show this help

Environment:
  DT_CLI_BASE_URL      Where to fetch install assets from
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --project|-p)    PROJECT="$2"; shift 2 ;;
    --api-url|-u)    API_URL="$2"; shift 2 ;;
    --version|-v)    VERSION="$2"; shift 2 ;;
    --with-browser)  WITH_BROWSER="true"; shift ;;
    --skip-checksum) SKIP_CHECKSUM="true"; shift ;;
    --uninstall)     UNINSTALL="true"; shift ;;
    --help|-h)       usage; exit 0 ;;
    *) fail "Unknown argument: $1 (try --help)" ;;
  esac
done

echo -e "${BOLD}detesting.ai CLI${RESET}"
echo ""

# ── uninstall ───────────────────────────────────────────────────────────────
if [[ "$UNINSTALL" == "true" ]]; then
  step "Removing @detesting.ai/cli"
  npm uninstall -g @detesting.ai/cli >/dev/null 2>&1 || true
  say "Uninstalled"
  echo -e "${DIM}  Config left in place: ~/.detesting.json, ~/.detesting-tokens.json${RESET}"
  exit 0
fi

# ── prerequisites ───────────────────────────────────────────────────────────
command -v node >/dev/null || fail "Node.js ${MIN_NODE_VERSION}+ is required. See https://nodejs.org"
command -v npm  >/dev/null || fail "npm is required (it ships with Node.js)"

NODE_MAJOR="$(node -v | sed 's/v//' | cut -d. -f1)"
if [[ "$NODE_MAJOR" -lt "$MIN_NODE_VERSION" ]]; then
  fail "Node.js ${MIN_NODE_VERSION}+ required, found $(node -v)"
fi
say "Node.js $(node -v)"

DOWNLOADER=""
if command -v curl >/dev/null; then DOWNLOADER="curl"
elif command -v wget >/dev/null; then DOWNLOADER="wget"
else fail "Need curl or wget to download the CLI"
fi

# ── download ────────────────────────────────────────────────────────────────
TARBALL_NAME="dt-cli-${VERSION}.tgz"
TARBALL_URL="${BASE_URL}/${TARBALL_NAME}"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT

step "Downloading ${TARBALL_NAME}"
if [[ "$DOWNLOADER" == "curl" ]]; then
  curl -fsSL "$TARBALL_URL" -o "${TMP_DIR}/${TARBALL_NAME}" \
    || fail "Could not download ${TARBALL_URL}"
else
  wget -q "$TARBALL_URL" -O "${TMP_DIR}/${TARBALL_NAME}" \
    || fail "Could not download ${TARBALL_URL}"
fi

# A tarball is a program about to run as you. If the publisher put a checksum
# next to it, check it. A missing checksum warns so an older upload still
# installs; a MISMATCHED one is fatal.
if [[ "$SKIP_CHECKSUM" != "true" ]] && command -v sha256sum >/dev/null; then
  if [[ "$DOWNLOADER" == "curl" ]]; then
    curl -fsSL "${TARBALL_URL}.sha256" -o "${TMP_DIR}/checksum" 2>/dev/null || true
  else
    wget -q "${TARBALL_URL}.sha256" -O "${TMP_DIR}/checksum" 2>/dev/null || true
  fi

  if [[ -s "${TMP_DIR}/checksum" ]]; then
    EXPECTED="$(awk '{print $1}' "${TMP_DIR}/checksum")"
    ACTUAL="$(sha256sum "${TMP_DIR}/${TARBALL_NAME}" | awk '{print $1}')"
    [[ "$EXPECTED" == "$ACTUAL" ]] \
      || fail "Checksum mismatch — refusing to install. Expected ${EXPECTED}, got ${ACTUAL}"
    say "Checksum verified"
  else
    warn "No checksum published for this version; skipping verification"
  fi
fi

# ── install ─────────────────────────────────────────────────────────────────
step "Installing"
if ! npm install -g "${TMP_DIR}/${TARBALL_NAME}" >"${TMP_DIR}/npm.log" 2>&1; then
  echo -e "${DIM}$(tail -20 "${TMP_DIR}/npm.log")${RESET}"
  # The usual cause on a system-owned prefix, and the fix people actually want
  if grep -qiE "EACCES|permission denied" "${TMP_DIR}/npm.log"; then
    fail "npm could not write to its global directory. Either re-run with sudo, or point npm somewhere you own:
    npm config set prefix ~/.local
    export PATH=\"\$HOME/.local/bin:\$PATH\""
  fi
  fail "npm install failed (log above)"
fi

# Ask npm from a neutral directory: inside a workspace `npm list -g` refuses
# with ENOWORKSPACES, printing an npm error over a successful install.
INSTALLED_VERSION="$(cd "$TMP_DIR" && npm list -g --depth=0 @detesting.ai/cli 2>/dev/null \
  | grep -o '@detesting.ai/cli@[0-9.]*' | cut -d'@' -f3 || true)"
say "Installed dt ${INSTALLED_VERSION:-$VERSION}"

# ── PATH ────────────────────────────────────────────────────────────────────
# `npm bin -g` was removed in npm 9, and its failure text is not a path
NPM_PREFIX="$(cd "$TMP_DIR" && npm config get prefix 2>/dev/null || echo "")"
if [[ -n "$NPM_PREFIX" && "$NPM_PREFIX" != "undefined" ]]; then
  NPM_BIN="${NPM_PREFIX}/bin"
else
  NPM_BIN="$(dirname "$(command -v npm)")"
fi
if ! command -v dt >/dev/null; then
  warn "dt is not on your PATH yet"
  echo -e "${DIM}  Add this to your shell profile:${RESET}"
  echo -e "    export PATH=\"${NPM_BIN}:\$PATH\""
fi

# ── optional: browser support ───────────────────────────────────────────────
if [[ "$WITH_BROWSER" == "true" ]]; then
  step "Downloading Chromium for local browser tests"
  if command -v dt >/dev/null; then
    dt browser install || warn "Chromium install failed — run 'dt browser install' later"
  else
    warn "dt is not on PATH yet; run 'dt browser install' once it is"
  fi
fi

# ── optional configuration ──────────────────────────────────────────────────
if [[ -n "$API_URL" || -n "$PROJECT" ]]; then
  CONFIG="${HOME}/.detesting.json"
  node -e "
    const fs = require('fs');
    const path = '${CONFIG}';
    let config = {};
    try { config = JSON.parse(fs.readFileSync(path, 'utf8')); } catch {}
    const apiUrl = '${API_URL}';
    const project = '${PROJECT}';
    if (apiUrl) config.apiUrl = apiUrl;
    if (project) config.project = project;
    fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
  "
  say "Wrote ${CONFIG}"
fi

echo ""
echo -e "${BOLD}Next${RESET}"
echo "  dt login                     sign in through BitBot"
echo "  dt project join <name>       bind this directory to a project"
echo "  dt env use local             pick a default environment"
echo "  dt suite run --all           run everything"
echo ""
if [[ "$WITH_BROWSER" != "true" ]]; then
  echo -e "${DIM}  Browser tests need Chromium (~300 MB):  dt browser install${RESET}"
fi
echo -e "${DIM}  Tab completion:  dt completion bash >> ~/.bashrc   (or zsh / fish)${RESET}"
echo -e "${DIM}  Uninstall:       curl -fsSL ${BASE_URL}/install.sh | bash -s -- --uninstall${RESET}"
echo ""
