#!/bin/sh
# Install the latest stable ComputeArena release, or newest staging prerelease
# only when no stable release exists. Requires curl, tar and Python 3.
set -eu
REPOSITORY=basecompute/computearena-cli
INSTALL_DIR="${COMPUTEARENA_INSTALL_DIR:-$HOME/.local/bin}"
# Palette matches computearena-cli/src/theme.rs. Disable ANSI for redirected
# output, NO_COLOR (including an empty value), and dumb terminals.
RESET= BRAND= NEUTRAL= DANGER= ACCENT=
if [ -t 1 ] && [ "${NO_COLOR+x}" != x ] && [ "${TERM:-}" != dumb ]; then
  RESET="$(printf '\033[0m')"
  BRAND="$(printf '\033[1;38;2;195;255;77m')"
  NEUTRAL="$(printf '\033[38;2;156;163;175m')"
  DANGER="$(printf '\033[1;38;2;255;95;95m')"
  ACCENT="$(printf '\033[1;38;2;124;192;222m')"
fi
RULE="────────────────────────────────────────────────────────────"
section() { printf '\n%s%s%s\n%s%s%s\n%s%s%s\n' "$NEUTRAL" "$RULE" "$RESET" "$BRAND" "$*" "$RESET" "$NEUTRAL" "$RULE" "$RESET"; }
activity() { printf '%s…%s %s\n' "$BRAND" "$RESET" "$*"; }
success() { printf '%s✓%s %s\n' "$BRAND" "$RESET" "$*"; }
info() { printf '%s\n' "$*"; }
fail() { printf '%s✗%s %s\n' "$DANGER" "$RESET" "$*" >&2; exit 1; }

section "ComputeArena installer"
info "This script downloads a prebuilt release from GitHub, verifies its SHA-256,"
info "and installs computearena to $INSTALL_DIR (no sudo or source compilation)."
info "It prefers the latest stable release; otherwise it uses the latest staging release."
info "An existing binary is kept as computearena.previous, replacing any earlier backup."
if [ "${COMPUTEARENA_NO_MODIFY_PATH:-0}" = 1 ]; then
  info "Shell profiles will not be changed (COMPUTEARENA_NO_MODIFY_PATH=1)."
else
  info "It adds the install directory to your shell profile and backs up an existing profile."
fi
info "Benchmark reports, login credentials, and runtime installations are not changed."
info ""

ASSUME_YES=0
LAUNCH=0
API_URL=
while [ "$#" -gt 0 ]; do
  case "$1" in
    --yes|-y) ASSUME_YES=1 ;;
    launch|--launch) LAUNCH=1 ;;
    --api-url)
      [ "$#" -ge 2 ] || fail "--api-url requires a URL ending in /api/v1"
      shift
      API_URL=$1
      case "$API_URL" in http://?*|https://?*) ;; *) fail "--api-url must use http:// or https://" ;; esac
      ;;
    *) fail "usage: install.sh [--yes] [launch|--launch [--api-url URL]]" ;;
  esac
  shift
done
if [ -n "$API_URL" ] && [ "$LAUNCH" != 1 ]; then
  fail "--api-url requires launch (or --launch)"
fi
if [ "$LAUNCH" = 1 ]; then
  # The downloaded script occupies stdin. The interactive CLI needs the
  # controlling terminal, and cannot depend on the parent shell's PATH.
  if ! ( : </dev/tty ) 2>/dev/null; then
    fail "launch requires an interactive terminal. Omit launch/--launch to install only."
  fi
  info "After installation, this command will open the ComputeArena interactive menu."
  [ -z "$API_URL" ] || info "The menu will connect to: $API_URL"
fi
# The terminal's own device, such as /dev/ttys003 or /dev/pts/3. The CLI
# watches its input through the system event queue, and macOS refuses to
# watch the /dev/tty alias (kqueue answers EINVAL), which the CLI reports as
# "Failed to initialize input reader". stdin is the downloaded script here,
# so the device is read from stderr or stdout, then from the process table;
# /dev/tty remains the last resort.
terminal_device() {
  for descriptor in 2 1; do
    if [ -t "$descriptor" ]; then
      device="$(tty <&"$descriptor" 2>/dev/null)" || device=
      if [ -n "$device" ] && [ "$device" != /dev/tty ] && [ -c "$device" ]; then
        printf '%s\n' "$device"
        return
      fi
    fi
  done
  device="/dev/$(ps -o tty= -p "$$" 2>/dev/null | tr -d ' ')"
  if [ -c "$device" ] && ( : <"$device" ) 2>/dev/null; then
    printf '%s\n' "$device"
    return
  fi
  printf '/dev/tty\n'
}
confirm_install() {
  if [ "$ASSUME_YES" = 1 ]; then
    info "Proceeding with explicit --yes permission."
    return
  fi
  # stdin contains the script for curl | sh. Always ask via the controlling
  # terminal, never consume shell source or interpret piped data as permission.
  if ! ( : </dev/tty ) 2>/dev/null; then
    fail "No interactive terminal. Nothing was changed. For unattended use: sh install.sh --yes"
  fi
  exec 3<>/dev/tty
  while :; do
    printf '\n%s›%s Proceed with installation? [y/N]: ' "$BRAND" "$RESET" >&3
    if ! IFS= read -r answer <&3; then
      info "Installation cancelled. Nothing was changed."
      exit 0
    fi
    case "$answer" in
      y|Y|yes|YES|Yes) exec 3>&-; return ;;
      ""|n|N|no|NO|No)
        info "Installation cancelled. Nothing was changed."
        exit 0 ;;
      *) printf '%sEnter y for yes or n for no.%s\n' "$ACCENT" "$RESET" >&3 ;;
    esac
  done
}
case "$INSTALL_DIR" in /*) ;; *) fail "COMPUTEARENA_INSTALL_DIR must be an absolute path" ;; esac
# Keep generated shell configuration literal and safe.
case "$INSTALL_DIR" in *"'"*|*'
'*) fail "installation path cannot contain a quote or newline" ;; esac
for tool in curl tar python3; do
  command -v "$tool" >/dev/null 2>&1 || fail "$tool is required; install it and rerun this script"
done
case "$(uname -s)" in Darwin) OS=macos ;; Linux) OS=linux ;; *) fail "supported systems: macOS and Linux" ;; esac
case "$(uname -m)" in arm64|aarch64) ARCH=arm64 ;; x86_64|amd64) ARCH=x86_64 ;; *) fail "unsupported CPU architecture" ;; esac
confirm_install
section "Installing ComputeArena"
activity "Checking available releases…"
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/computearena-install.XXXXXX")"
# Temporary names in the install directory live only until their rename; an
# interrupted run must not leave them behind.
STAGED= BACKUP=
cleanup() {
  [ ! -d "$WORK_DIR" ] || rm -rf -- "$WORK_DIR"
  [ -z "$STAGED" ] || rm -f -- "$STAGED"
  [ -z "$BACKUP" ] || rm -f -- "$BACKUP"
}
trap cleanup 0
trap 'exit 130' INT
trap 'exit 143' TERM HUP

# Fetch all pages so a long series of prereleases cannot hide a stable release.
page=1
while :; do
  curl --proto '=https' --proto-redir '=https' -fLsS --retry 3 \
    "https://api.github.com/repos/$REPOSITORY/releases?per_page=100&page=$page" \
    -o "$WORK_DIR/page-$page.json"
  count="$(python3 -c 'import json,sys; x=json.load(open(sys.argv[1])); assert isinstance(x,list), "invalid release response"; print(len(x))' "$WORK_DIR/page-$page.json")"
  [ "$count" -eq 100 ] || break
  page=$((page + 1))
done
python3 - "$WORK_DIR" "$OS" "$ARCH" > "$WORK_DIR/selection" <<'PY'
import glob, json, re, sys
root, os_name, arch = sys.argv[1:]
releases = [r for path in glob.glob(root + "/page-*.json")
            for r in json.load(open(path)) if not r.get("draft")]
stable = [r for r in releases if not r.get("prerelease")]
staging = [r for r in releases if r.get("prerelease") and r.get("tag_name", "").startswith("staging-")]
candidates = stable or staging
if not candidates:
    sys.exit("No stable or staging ComputeArena release is available.")
release = max(candidates, key=lambda r: r.get("published_at") or "")
pattern = re.compile(r"computearena-" + re.escape(os_name + "-" + arch) + r"-[A-Za-z0-9._-]+\.tar\.gz")
assets = [a for a in release.get("assets", []) if pattern.fullmatch(a["name"])]
if len(assets) != 1:
    sys.exit("Latest release has no unique binary for " + os_name + "/" + arch + "; no older release was silently substituted.")
asset = assets[0]
digest = asset.get("digest") or ""
if not re.fullmatch(r"sha256:[0-9a-f]{64}", digest):
    sys.exit("Release asset lacks a valid GitHub SHA-256 digest; refusing unverified installation.")
url = asset["browser_download_url"]
if not url.startswith("https://github.com/basecompute/computearena-cli/releases/download/") or any(c.isspace() for c in url):
    sys.exit("Unexpected release download URL.")
print("staging" if release["prerelease"] else "stable")
print(url)
print(digest[7:])
PY
CHANNEL="$(sed -n '1p' "$WORK_DIR/selection")"
URL="$(sed -n '2p' "$WORK_DIR/selection")"
DIGEST="$(sed -n '3p' "$WORK_DIR/selection")"
info "Selected $CHANNEL release: $URL"
[ "$CHANNEL" != staging ] || info "Warning: no stable release exists. This is a prerelease for testing."
activity "Downloading the $OS/$ARCH binary…"
curl --proto '=https' --proto-redir '=https' -fLsS --retry 3 "$URL" -o "$WORK_DIR/bundle.tar.gz"
activity "Verifying archive integrity…"
python3 - "$WORK_DIR/bundle.tar.gz" "$DIGEST" <<'PY'
import hashlib, sys
with open(sys.argv[1], "rb") as f:
    digest = hashlib.file_digest(f, "sha256").hexdigest() if hasattr(hashlib, "file_digest") else None
    if digest is None:
        f.seek(0)
        h = hashlib.sha256()
        for block in iter(lambda: f.read(1024 * 1024), b""):
            h.update(block)
        digest = h.hexdigest()
if digest != sys.argv[2]:
    sys.exit("Archive checksum mismatch; nothing was installed.")
PY
# Extract only the expected regular binary, never archive paths or symlinks.
python3 - "$WORK_DIR/bundle.tar.gz" <<'PY'
import sys, tarfile
with tarfile.open(sys.argv[1], "r:gz") as archive:
    matches = [m for m in archive.getmembers() if m.name == "computearena"]
    if len(matches) != 1 or not matches[0].isfile():
        sys.exit("Archive does not contain one regular computearena binary.")
PY
success "Archive verified"
activity "Installing the binary…"
tar -xOf "$WORK_DIR/bundle.tar.gz" computearena > "$WORK_DIR/computearena"
mkdir -p "$INSTALL_DIR"
if [ -e "$INSTALL_DIR/computearena" ]; then
  # Keep exactly one earlier version. The copy is written under a temporary
  # name and renamed into place, so an earlier backup is replaced in one step
  # and an interrupted upgrade never leaves a partial one. Refusing here
  # instead would block every upgrade after the first.
  [ ! -d "$INSTALL_DIR/computearena.previous" ] || fail "computearena.previous is a directory; move it aside before upgrading"
  BACKUP="$(mktemp "$INSTALL_DIR/.computearena.previous.XXXXXX")"
  cp -p "$INSTALL_DIR/computearena" "$BACKUP"
  mv -f "$BACKUP" "$INSTALL_DIR/computearena.previous"
fi
STAGED="$(mktemp "$INSTALL_DIR/.computearena.XXXXXX")"
install -m 755 "$WORK_DIR/computearena" "$STAGED"
mv -f "$STAGED" "$INSTALL_DIR/computearena"

if [ "${COMPUTEARENA_NO_MODIFY_PATH:-0}" != 1 ]; then
  case "${SHELL:-/bin/sh}" in
    */zsh) PROFILE="${ZDOTDIR:-$HOME}/.zshrc" ;;
    */bash)
      PROFILE="$HOME/.bashrc"
      [ "$OS" != macos ] || PROFILE="$HOME/.bash_profile"
      ;;
    */fish) PROFILE="$HOME/.config/fish/conf.d/computearena.fish" ;;
    *) PROFILE="$HOME/.profile" ;;
  esac
  mkdir -p "$(dirname "$PROFILE")"
  if [ ! -f "$PROFILE" ] || ! grep -Fq "# ComputeArena PATH: $INSTALL_DIR" "$PROFILE"; then
    if [ -f "$PROFILE" ]; then
      PROFILE_BACKUP="$(mktemp "$PROFILE.computearena-backup.XXXXXX")"
      cp -p "$PROFILE" "$PROFILE_BACKUP"
      info "Shell profile backup: $PROFILE_BACKUP"
    fi
    case "${SHELL:-/bin/sh}" in
      */fish) printf "\n# ComputeArena PATH: %s\nfish_add_path -- '%s'\n" "$INSTALL_DIR" "$INSTALL_DIR" >> "$PROFILE" ;;
      *) printf "\n# ComputeArena PATH: %s\nexport PATH='%s':\"\$PATH\"\n" "$INSTALL_DIR" "$INSTALL_DIR" >> "$PROFILE" ;;
    esac
  fi
  info "PATH configured in $PROFILE."
fi
section "Ready"
success "Installed: $INSTALL_DIR/computearena"
info "Open a new terminal, or activate it in this terminal:"
case "${SHELL:-/bin/sh}" in
  */fish) info "  fish_add_path -- '$INSTALL_DIR'" ;;
  *) info "  export PATH='$INSTALL_DIR':\$PATH" ;;
esac
info "Then start: computearena"
if [ "$LAUNCH" = 1 ]; then
  info ""
  activity "Opening ComputeArena…"
  TERMINAL="$(terminal_device)"
  # exec does not run the exit trap: remove download files before launching.
  cleanup
  trap - 0
  if [ -n "$API_URL" ]; then
    exec "$INSTALL_DIR/computearena" --api-url "$API_URL" <"$TERMINAL"
  else
    exec "$INSTALL_DIR/computearena" <"$TERMINAL"
  fi
fi
