#!/usr/bin/env bash
# Install or uninstall the public Helix binary.
#
# The binary goes to ~/.mutagent/bin and is symlinked into ~/.local/bin (or ~/bin
# when only that is on PATH). The installer never writes to a shell rc or profile
# file and never changes PATH; when the link dir is not on PATH it prints the
# command to run yourself.
#
# Environment:
#   MUTAGENT_HELIX_CHANNEL      Release channel to install: latest or candidate.
#   MUTAGENT_HELIX_BASE_URL     Explicit asset base URL override.
#   MUTAGENT_INSTALL_HOST       Installer host. Defaults to https://install.mutagent.io.
#   MUTAGENT_INSTALL_DIR        Install dir. Defaults to ~/.mutagent/bin.
#   MUTAGENT_NO_MODIFY_PATH=1   Do not symlink helix into ~/.local/bin or ~/bin (same as --no-modify-path).
#   NO_COLOR                    Disable colored/branded output.
#   MUTAGENT_INTERNAL=1         Marks the install as the MutagenT team's (internal=1 in the User-Agent).

set -euo pipefail

# Revision of THIS script, sent in the User-Agent. The release copies the file to
# the install host verbatim, so nothing stamps it: bump it by hand when the
# script's behaviour changes.
INSTALLER_VERSION="2"

BINARY="${MUTAGENT_HELIX_BINARY:-helix}"
FLAVOR="${MUTAGENT_HELIX_FLAVOR:-pi}"
INSTALL_SLUG="${MUTAGENT_HELIX_INSTALL_SLUG:-helix}"
INSTALL_DIR="${MUTAGENT_INSTALL_DIR:-$HOME/.mutagent/bin}"
INSTALL_HOST="${MUTAGENT_INSTALL_HOST:-https://install.mutagent.io}"
CHANNEL="${MUTAGENT_HELIX_CHANNEL:-${MUTAGENT_HELIX_VERSION:-latest}}"
NO_MODIFY_PATH="${MUTAGENT_NO_MODIFY_PATH:-0}"
INSTALLER_TMPDIR=""
PLATFORM=""
BASE_URL_RESOLVED=""

# ── presentation (all guarded on a real TTY + NO_COLOR) ───────────────────────
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-}" != "dumb" ]; then
  IS_TTY=1
else
  IS_TTY=0
fi
RESET=""; DIM=""; BOLD=""; CYAN=""; VIOLET=""; GREEN=""; RED=""; MUTED=""
TRUECOLOR=0
if [ "$IS_TTY" = 1 ]; then
  RESET=$'\033[0m'; DIM=$'\033[2m'; BOLD=$'\033[1m'
  GREEN=$'\033[32m'; RED=$'\033[31m'; MUTED=$'\033[90m'
  case "${COLORTERM:-}" in
    *truecolor*|*24bit*) TRUECOLOR=1; CYAN=$'\033[38;2;69;184;204m'; VIOLET=$'\033[38;2;126;71;215m' ;;
    *) CYAN=$'\033[36m'; VIOLET=$'\033[35m' ;;
  esac
fi

banner() {
  if [ "$IS_TTY" != 1 ]; then
    printf '\n  MUTAGENT · HELIX — ADLC Orchestrator\n\n'
    return
  fi
  local rows=(
    " ███╗   ███╗ ██╗   ██╗ ████████╗  █████╗   ██████╗  ███████╗ ███╗   ██╗ ████████╗ "
    " ████╗ ████║ ██║   ██║ ╚══██╔══╝ ██╔══██╗ ██╔════╝  ██╔════╝ ████╗  ██║ ╚══██╔══╝ "
    " ██╔████╔██║ ██║   ██║    ██║    ███████║ ██║  ███╗ █████╗   ██╔██╗ ██║    ██║     "
    " ██║╚██╔╝██║ ██║   ██║    ██║    ██╔══██║ ██║   ██║ ██╔══╝   ██║╚██╗██║    ██║     "
    " ██║ ╚═╝ ██║ ╚██████╔╝    ██║    ██║  ██║ ╚██████╔╝ ███████╗ ██║ ╚████║    ██║     "
    " ╚═╝     ╚═╝  ╚═════╝     ╚═╝    ╚═╝  ╚═╝  ╚═════╝  ╚══════╝ ╚═╝  ╚═══╝    ╚═╝     "
  )
  local grad=(
    $'\033[38;2;69;184;204m' $'\033[38;2;80;161;206m' $'\033[38;2;92;139;208m'
    $'\033[38;2;103;116;210m' $'\033[38;2;114;94;212m' $'\033[38;2;126;71;215m'
  )
  echo
  local i
  for i in 0 1 2 3 4 5; do
    if [ "$TRUECOLOR" = 1 ]; then
      printf '%s%s%s\n' "${grad[$i]}" "${rows[$i]}" "$RESET"
    else
      printf '%s%s%s\n' "$CYAN" "${rows[$i]}" "$RESET"
    fi
  done
  printf '%s          Helix · ADLC Orchestrator · build · evaluate · diagnose · evolve%s\n\n' "$MUTED" "$RESET"
}

STEP_N=0
STEP_TOTAL=5
step()  { STEP_N=$((STEP_N + 1)); printf '  %s[%d/%d]%s %s… ' "$MUTED" "$STEP_N" "$STEP_TOTAL" "$RESET" "$1"; }
ok()    { printf '%s✓%s %s\n' "$GREEN" "$RESET" "${1:-}"; }
skip()  { printf '%s↷%s %s\n' "$MUTED" "$RESET" "${1:-}"; }

fail() {
  # fail <what> [reason] [remediation] — always to stderr (never captured by $())
  printf '\n  %s✗ install failed%s — %s\n' "$RED" "$RESET" "$1" >&2
  [ -n "${2:-}" ] && printf '      %s\n' "$2" >&2
  [ -n "${3:-}" ] && printf '      %s→%s %s\n' "$CYAN" "$RESET" "$3" >&2
  echo >&2
  exit 1
}

detect_platform() {   # sets $PLATFORM in the main shell (fail() must not be swallowed by $())
  local os arch
  case "$(uname -s)" in
    Linux*) os="linux" ;;
    Darwin*) os="darwin" ;;
    *) fail "unsupported OS: $(uname -s)" "Only Linux and macOS are supported." "Use a Linux or macOS host." ;;
  esac
  case "$(uname -m)" in
    x86_64|amd64) arch="x64" ;;
    arm64|aarch64) arch="arm64" ;;
    *) fail "unsupported architecture: $(uname -m)" "Only x64 and arm64 are supported." "Use an x64 or arm64 host." ;;
  esac
  PLATFORM="${os}-${arch}"
}

usage() {
  cat <<EOF
Usage:
  $BINARY installer [install] [--no-modify-path]
  $BINARY installer uninstall [--purge]
  $BINARY installer --help

Examples:
  curl -fsSL ${INSTALL_HOST%/}/${INSTALL_SLUG} | bash
  curl -fsSL ${INSTALL_HOST%/}/${INSTALL_SLUG} | bash -s -- --no-modify-path
  curl -fsSL ${INSTALL_HOST%/}/${INSTALL_SLUG} | bash -s -- uninstall --purge

Environment:
  MUTAGENT_HELIX_CHANNEL     latest or candidate (default: latest)
  MUTAGENT_HELIX_BASE_URL    explicit asset base URL
  MUTAGENT_INSTALL_DIR       install directory (default: ~/.mutagent/bin)
  MUTAGENT_NO_MODIFY_PATH=1  do not symlink helix into ~/.local/bin or ~/bin
  NO_COLOR                   disable branded/colored output

The binary is installed to ~/.mutagent/bin and symlinked into ~/.local/bin (or ~/bin).
No shell rc or profile file is ever written.
EOF
}

# Refuse plaintext HTTP for a non-loopback host. checksums.txt and the binary
# share an origin, so a MITM on that origin controls BOTH — the checksum proves
# nothing. Loopback stays allowed (local mirrors / tests); anything else needs an
# explicit, documented opt-in. Mirrored in the binary's `update` command.
assert_secure_url() {
  case "$1" in
    https://*) return 0 ;;
    http://localhost|http://localhost:*|http://localhost/*) return 0 ;;
    http://127.0.0.1|http://127.0.0.1:*|http://127.0.0.1/*) return 0 ;;
    http://[::1]|http://[::1]:*|http://[::1]/*) return 0 ;;
    http://*)
      [ "${MUTAGENT_HELIX_ALLOW_INSECURE:-}" = "1" ] && return 0
      fail "refusing plaintext HTTP: $1" \
           "checksums.txt and the binary share an origin, so a network attacker who can rewrite one can rewrite the other — the checksum would verify an attacker's build." \
           "Use https://, or set MUTAGENT_HELIX_ALLOW_INSECURE=1 if you genuinely intend an insecure transport." ;;
    *) fail "unsupported URL scheme: $1" "Only https:// (and loopback http://) are accepted." "Set MUTAGENT_HELIX_BASE_URL to an https:// URL." ;;
  esac
}

resolve_base_url() {   # sets $BASE_URL_RESOLVED in the main shell (fail() runs here, not in $())
  if [ -n "${MUTAGENT_HELIX_BASE_URL:-}" ]; then
    BASE_URL_RESOLVED="${MUTAGENT_HELIX_BASE_URL%/}"; assert_secure_url "$BASE_URL_RESOLVED"; return
  fi
  case "$CHANNEL" in
    latest|candidate) BASE_URL_RESOLVED="${INSTALL_HOST%/}/${CHANNEL}" ;;
    *) fail "unknown channel: ${CHANNEL}" "Only 'latest' and 'candidate' are retained on the installer host." "Set MUTAGENT_HELIX_CHANNEL=latest (or candidate)." ;;
  esac
  assert_secure_url "$BASE_URL_RESOLVED"
}
asset_url() { echo "${BASE_URL_RESOLVED}/$1"; }

require_curl() {
  command -v curl >/dev/null 2>&1 || fail "curl is required" "The installer fetches the binary over HTTPS with curl." "Install curl (e.g. 'brew install curl' / 'apt install curl'), then re-run."
}
# Every request names itself, so the install host's analytics can tell a person's
# install from CI, a team machine, `helix update` or the CLI installer. The header
# rides on requests the installer makes anyway: no extra request, nothing else sent.
#   helix-installer/<version> (<os>-<arch>; ch=<channel>; ci=<0|1>; internal=<0|1>)
# A channel other than latest|candidate (reachable only with MUTAGENT_HELIX_BASE_URL)
# goes out as "custom": the header never carries free text from the environment.
user_agent() {
  local ch ci=0 internal=0
  case "$CHANNEL" in latest|candidate) ch="$CHANNEL" ;; *) ch="custom" ;; esac
  if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then ci=1; fi
  if [ "${MUTAGENT_INTERNAL:-}" = "1" ]; then internal=1; fi
  printf 'helix-installer/%s (%s; ch=%s; ci=%s; internal=%s)' "$INSTALLER_VERSION" "$PLATFORM" "$ch" "$ci" "$internal"
}
download_quiet() { curl -fsSL -A "$(user_agent)" "$1" -o "$2"; }
download_progress() {
  # progress bar only when attached to a TTY; quiet otherwise (curl|bash pipes)
  if [ "$IS_TTY" = 1 ]; then
    printf '\n'; curl -fSL --progress-bar -A "$(user_agent)" "$1" -o "$2"
  else
    curl -fsSL -A "$(user_agent)" "$1" -o "$2"
  fi
}

verify_checksum() {
  local asset="$1" file="$2" tmpdir="$3"
  local sums="${tmpdir}/checksums.txt"
  download_quiet "$(asset_url checksums.txt)" "$sums" \
    || fail "checksums.txt unavailable" "Refusing to install an unverifiable binary." "Check MUTAGENT_HELIX_CHANNEL / network, then retry."
  local expected
  expected="$(grep "  ${asset}$" "$sums" | awk '{print $1}' || true)"
  [ -n "$expected" ] || fail "checksum missing for ${asset}" "${asset} is not listed in checksums.txt." "This release has no build for ${PLATFORM}. Check MUTAGENT_HELIX_CHANNEL (currently ${CHANNEL}), then retry."
  local actual
  if command -v sha256sum >/dev/null 2>&1; then
    actual="$(sha256sum "$file" | awk '{print $1}')"
  else
    actual="$(shasum -a 256 "$file" | awk '{print $1}')"
  fi
  [ "$actual" = "$expected" ] || fail "checksum mismatch for ${asset}" "expected ${expected}; got ${actual}." "Retry the download; if it persists try MUTAGENT_HELIX_CHANNEL=candidate."
}

cache_root() {
  if [ -n "${MUTAGENT_HELIX_RUNTIME_DIR:-}" ]; then echo "$MUTAGENT_HELIX_RUNTIME_DIR"
  elif [ -n "${XDG_CACHE_HOME:-}" ]; then echo "$XDG_CACHE_HOME/mutagent/helix"
  elif [ "$(uname -s)" = "Darwin" ]; then echo "$HOME/Library/Caches/mutagent/helix"
  else echo "$HOME/.cache/mutagent/helix"; fi
}

# ── the helix symlink (PATH is never modified) ────────────────────────────────
# The installer NEVER writes to a shell rc or profile file and never changes PATH.
# It symlinks the binary into ~/.local/bin (created if missing), or into ~/bin when
# ~/bin is on PATH and ~/.local/bin is not. When the link directory is not on PATH,
# it prints one command the user can run themselves plus the absolute launch path;
# nothing is written on their behalf. (`curl | bash` is a child process anyway: it
# could not change the calling terminal's PATH even if it tried.)
PATH_RESULT=""   # human-readable note set by configure_path
PATH_HINT=""     # the one command that puts the link dir on PATH; printed, never run or written
PATH_NOTE=""     # why the symlink was not made, when a foreign file blocked it
LAUNCH_CMD=""    # the command that runs helix in THIS terminal (bare name or absolute path)

# A literal "~" via prefix-strip. A pattern substitution with "~" as the replacement is
# NOT portable: bash 5.2 tilde-expands
# the replacement back to $HOME, so nothing collapsed on Linux.
tilde() { case "$1" in "$HOME"|"$HOME"/*) printf '~%s\n' "${1#"$HOME"}" ;; *) printf '%s\n' "$1" ;; esac; }

# Directories we may link into. Only per-user dirs — never /usr/local/bin,
# /opt/homebrew/bin or any system dir, and never sudo. Uninstall checks both.
link_candidates() { echo "$HOME/.local/bin"; echo "$HOME/bin"; }

on_path() { case ":$PATH:" in *":$1:"*) return 0 ;; *) return 1 ;; esac; }

# ~/.local/bin, unless ~/bin is on PATH and ~/.local/bin is not.
pick_link_dir() {
  if ! on_path "$HOME/.local/bin" && on_path "$HOME/bin"; then
    echo "$HOME/bin"
  else
    echo "$HOME/.local/bin"
  fi
}

# link_onto_path <dir> — symlink the binary this run installed into <dir>, creating
# <dir> if needed. (One binary: the legacy `mutagent-helix` alias stays inside
# INSTALL_DIR only.) An existing symlink to our binary is success (re-runs are
# idempotent). Anything else at that name — a regular file, or a symlink pointing
# elsewhere — is left exactly as it is, and the caller reports it.
link_onto_path() {
  local dir="$1" src link
  src="${INSTALL_DIR}/${BINARY}"
  link="${dir}/${BINARY}"
  mkdir -p "$dir" 2>/dev/null || { PATH_NOTE="could not create $(tilde "$dir")"; return 1; }
  if [ -L "$link" ]; then
    if [ "$(readlink "$link")" != "$src" ]; then
      PATH_NOTE="$(tilde "$link") already exists and points elsewhere — left untouched"
      return 1
    fi
  elif [ -e "$link" ]; then
    PATH_NOTE="$(tilde "$link") already exists and is not our symlink — left untouched"
    return 1
  else
    ln -s "$src" "$link" || { PATH_NOTE="could not create $(tilde "$link")"; return 1; }
  fi
  PATH_RESULT="linked $(tilde "$link") → $(tilde "$src")"
}

# The absolute launch path, printed with ~ so it pastes as-is into any shell.
absolute_launch() { tilde "${INSTALL_DIR}/${BINARY}"; }

# A directory as the user should type it: $HOME-relative when it is under HOME.
dir_for_shell() {
  case "$1" in
    "$HOME"/*) echo "\$HOME${1#"$HOME"}" ;;
    *) echo "$1" ;;
  esac
}

# The command that puts <dir> on PATH in the user's current shell. Printed only:
# the installer never runs it for them and never writes it to a file.
path_command() {
  case "${SHELL:-}" in
    */fish) echo "set -gx PATH \"$(dir_for_shell "$1")\" \$PATH" ;;
    *)      echo "export PATH=\"$(dir_for_shell "$1"):\$PATH\"" ;;
  esac
}

configure_path() {
  # Opting out covers the symlink too: nothing is linked, nothing is written.
  if [ "$NO_MODIFY_PATH" = 1 ]; then
    PATH_RESULT="skipped (--no-modify-path) — no symlink made, nothing written"
    if on_path "$INSTALL_DIR"; then LAUNCH_CMD="$BINARY"; else LAUNCH_CMD="$(absolute_launch)"; fi
    return 0
  fi
  local dir
  dir="$(pick_link_dir)"
  if link_onto_path "$dir"; then
    if on_path "$dir" || on_path "$INSTALL_DIR"; then
      LAUNCH_CMD="$BINARY"
    else
      PATH_HINT="$(tilde "$dir") is not on your PATH and no shell file was changed. To add it, run: $(path_command "$dir")"
      LAUNCH_CMD="$(absolute_launch)"
    fi
    return 0
  fi
  # The link was blocked (a foreign file, or the dir could not be created). The
  # note says why; launch by the absolute path unless the install dir is on PATH.
  PATH_RESULT="not linked"
  if on_path "$INSTALL_DIR"; then LAUNCH_CMD="$BINARY"; else LAUNCH_CMD="$(absolute_launch)"; fi
}

# ── the branded coding-agent directive (fallback if the binary can't render) ──
#
# Every command it names is $LAUNCH_CMD: one that works in THIS terminal — the bare
# name when helix resolves on PATH, the absolute path when it does not.
fallback_directive() {
  local target="$1" run="${LAUNCH_CMD:-$BINARY}"
  echo
  printf '  %sLaunch%s   %s%s%s\n' "$BOLD" "$RESET" "$CYAN" "$run" "$RESET"
  printf '  %sVerify%s   %s doctor\n' "$BOLD" "$RESET" "$run"
  echo
  printf '  %s┄┄ Coding-Agent Directive ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄%s\n' "$VIOLET" "$RESET"
  printf '  Helix is installed at %s.\n' "$target"
  printf '  Run %s%s%s in a project → it boots the ADL orchestrator.\n' "$CYAN" "$run" "$RESET"
  if [ "$run" != "$BINARY" ]; then
    printf '  %s%s%s is not on your PATH, so launch it by the path above.\n' "$CYAN" "$BINARY" "$RESET"
  fi
  printf '  Drive it with %s/spec, /build, /evaluate, /diagnose%s.\n' "$BOLD" "$RESET"
  printf '  Verify anytime with %s%s doctor%s.\n' "$MUTED" "$run" "$RESET"
  echo
}

finish() {
  local target="$1"
  echo
  printf '  %s%s✓ Helix installed%s  %s→ %s%s\n' "$BOLD" "$GREEN" "$RESET" "$MUTED" "$target" "$RESET"
  [ -n "$PATH_RESULT" ] && printf '  %sLink%s     %s\n' "$BOLD" "$RESET" "$PATH_RESULT"
  [ -n "$PATH_HINT" ] && printf '  %sPATH%s     %s\n' "$BOLD" "$RESET" "$PATH_HINT"
  # Hand off to the binary for the branded welcome + directive (its wordmark is
  # suppressed — we already printed one). Only if the binary supports `--welcome`
  # (grep its --help); older binaries fall back to the installer-rendered directive.
  # The binary's welcome always names the bare `helix`, so it is used only when
  # the bare name resolves in this terminal; otherwise our directive, which names
  # the absolute path, is the one that tells the truth.
  if [ "${LAUNCH_CMD:-$BINARY}" = "$BINARY" ] && [ -x "$target" ] && "$target" --help 2>/dev/null | grep -q -- "--welcome"; then
    MUTAGENT_HELIX_NO_BANNER=1 "$target" doctor --welcome || fallback_directive "$target"
  else
    fallback_directive "$target"
  fi
}

# TRANSITION COMPAT (D8, one release) — see the call site in install_binary.
# BINARY is always "helix" or "helix-omp"; the old name was always
# "mutagent-${BINARY}" (mutagent-helix / mutagent-helix-omp), so the mapping
# is a plain prefix. Never clobbers a real file that isn't already our symlink
# — e.g. a leftover pre-rename binary of that name — the user's own file wins.
link_compat_alias() {
  local new_target="$1" old_name="mutagent-${BINARY}" old_path
  old_path="${INSTALL_DIR}/${old_name}"
  if [ -e "$old_path" ] && [ ! -L "$old_path" ]; then
    printf '  %s⚠%s %s exists and is not a symlink — leaving it untouched\n' "$RED" "$RESET" "$old_path"
    return 0
  fi
  ln -sf "$new_target" "$old_path"
  printf '  %s✓%s legacy alias %s still works (use %s%s%s)\n' "$GREEN" "$RESET" "$(tilde "$old_path")" "$CYAN" "$BINARY" "$RESET"
}

install_binary() {
  banner
  require_curl
  resolve_base_url

  step "Detecting platform"
  local asset tmpdir target
  detect_platform; ok "$PLATFORM"

  asset="${BINARY}-${PLATFORM}"
  tmpdir="$(mktemp -d)"; INSTALLER_TMPDIR="$tmpdir"
  trap 'if [ -n "$INSTALLER_TMPDIR" ]; then rm -rf "$INSTALLER_TMPDIR"; fi' EXIT
  mkdir -p "$INSTALL_DIR"

  step "Downloading ${asset}"
  download_progress "$(asset_url "$asset")" "${tmpdir}/${asset}" \
    || fail "download failed for ${asset}" "Could not fetch $(asset_url "$asset")." "Check your network and MUTAGENT_HELIX_CHANNEL (currently ${CHANNEL}), then retry."
  ok

  step "Verifying checksum"
  verify_checksum "$asset" "${tmpdir}/${asset}" "$tmpdir"; ok

  step "Installing binary"
  target="${INSTALL_DIR}/${BINARY}"
  install -m 0755 "${tmpdir}/${asset}" "$target" \
    || fail "could not write ${target}" "The install directory is not writable." "Set MUTAGENT_INSTALL_DIR to a writable path, then retry."
  ok "$(tilde "$target")"

  # TRANSITION COMPAT (D8, one release): 0.0.18-m0 and earlier shipped as
  # mutagent-helix / mutagent-helix-omp. An old install, a saved script, or a
  # shell alias baked from an earlier `setup-aliases.sh` run may still invoke
  # the old name — symlink it to the renamed binary so it keeps working.
  # Remove this block (and the mirror in uninstall_binary) once every install
  # has had a chance to pick up the rename via `helix update` / a fresh curl.
  link_compat_alias "$target"

  step "Linking ${BINARY}"
  configure_path
  case "$PATH_RESULT" in
    skipped*|"not linked") skip "$PATH_RESULT" ;;
    *)                     ok "$PATH_RESULT" ;;
  esac
  [ -n "$PATH_NOTE" ] && printf '  %s⚠%s %s; launch helix by its absolute path\n' "$RED" "$RESET" "$PATH_NOTE"

  finish "$target"
}

uninstall_binary() {
  local target="${INSTALL_DIR}/${BINARY}"
  if [ -e "$target" ]; then rm -f "$target"; printf '  %s✓%s removed %s\n' "$GREEN" "$RESET" "$target"
  else printf '  %s%s is not installed at %s%s\n' "$MUTED" "$BINARY" "$target" "$RESET"; fi
  # Mirror of link_compat_alias in install_binary — only remove OUR symlink,
  # never a real file a user happens to have at the old name.
  local old_path="${INSTALL_DIR}/mutagent-${BINARY}"
  if [ -L "$old_path" ]; then rm -f "$old_path"; printf '  %s✓%s removed compat symlink %s\n' "$GREEN" "$RESET" "$old_path"; fi
  # Mirror of link_onto_path — remove the helix symlinks only where they point at
  # OUR binary. Checked in every candidate dir, on PATH or not: PATH may differ
  # from the shell that installed. Shell rc files are never read or edited here:
  # a PATH line an older installer appended stays until the user removes it.
  local dir link
  while IFS= read -r dir; do
    link="${dir}/${BINARY}"
    if [ -L "$link" ] && [ "$(readlink "$link")" = "$target" ]; then
      rm -f "$link"; printf '  %s✓%s removed PATH symlink %s\n' "$GREEN" "$RESET" "$(tilde "$link")"
    fi
  done < <(link_candidates)
}
purge_runtime_cache() {
  local root; root="$(cache_root)"
  [ -d "$root" ] || return 0
  find "$root" -maxdepth 1 -type d -name "*-${FLAVOR}" -exec rm -rf {} +
  printf '  %s✓%s purged the %s runtime cache under %s\n' "$GREEN" "$RESET" "$BINARY" "$root"
}

# helix-omp is RETIRED: no omp asset is published any more. The flavour plumbing
# below still exists (an installed helix-omp can still be uninstalled with it),
# so refuse an INSTALL of it explicitly rather than letting it fail later on a
# "checksum missing" that explains nothing.
assert_flavor_still_published() {
  case "${BINARY}:${FLAVOR}" in
    *omp*|*:omp)
      fail "helix-omp is retired" \
           "helix-omp is no longer built or published; its capabilities are moving into helix." \
           "Install helix instead: curl -fsSL ${INSTALL_HOST%/}/helix | bash" ;;
  esac
}

main() {
  local action="install" purge="false"
  while [ $# -gt 0 ]; do
    case "$1" in
      --no-modify-path) NO_MODIFY_PATH=1 ;;
      --purge) purge="true" ;;
      install|uninstall) action="$1" ;;
      --help|-h|help) action="help" ;;
      *) fail "unknown option: $1" "" "Run with --help for usage." ;;
    esac
    shift
  done
  case "$action" in
    install)   assert_flavor_still_published; install_binary ;;
    uninstall) uninstall_binary; [ "$purge" = "true" ] && purge_runtime_cache || true ;;
    help)      usage ;;
  esac
}

main "$@"
