#!/bin/sh
# fremforge CLI installer.
#
# One-line install (published canonically at https://cli.frem.sh/cli/install.sh):
#
#   curl -sSfL https://cli.frem.sh/cli/install.sh | sh
#
# What this script does:
#   1. Detects OS + arch (darwin/linux × arm64/x86_64).
#   2. Downloads the matching binary from https://cli.frem.sh/.
#   3. Downloads the canonical SHA256SUMS from https://trust.frem.sh/
#      (SEPARATE host, SEPARATE bucket, SEPARATE writer credential —
#      compromising the binary host alone cannot forge a match).
#   4. Verifies the binary checksum against SHA256SUMS using whichever
#      of `sha256sum` / `shasum -a 256` is available.
#   5. Installs to ${FREMFORGE_INSTALL_DIR:-$HOME/.local/bin} (no sudo)
#      OR /usr/local/bin (with sudo if writable / sudo present).
#
# Environment knobs:
#   FREMFORGE_INSTALL_DIR    — install location override
#   FREMFORGE_VERSION        — pin a specific version (default: latest)
#   FREMFORGE_BIN_HOST       — override the binary host (default cli.frem.sh)
#   FREMFORGE_TRUST_HOST     — override the trust host (default trust.frem.sh)
#
#   NOTE: overriding either host also disables the no_proxy scoping below, on
#   the assumption that a custom host is internal and your no_proxy is what
#   reaches it.
#   FREMFORGE_SKIP_VERIFY    — set to 1 to skip SHA verification (NOT recommended)
#
# Why POSIX `sh` (not bash) — curl|sh has to run on minimal Alpine /
# scratch containers + bare macOS where /bin/sh is sometimes dash.
# Tested against dash, bash 5, zsh, busybox sh.
#
# Why a single self-contained script — no apt/brew dependency, no
# Node toolchain. Customer runs one curl line, gets a working CLI.

set -eu

BIN_HOST="${FREMFORGE_BIN_HOST:-https://cli.frem.sh}"
TRUST_HOST="${FREMFORGE_TRUST_HOST:-https://trust.frem.sh}"
VERSION="${FREMFORGE_VERSION:-latest}"
SKIP_VERIFY="${FREMFORGE_SKIP_VERIFY:-0}"

log() { printf '%s\n' "fremforge-install: $*" >&2; }
die() { log "ERROR: $*"; exit 1; }

# ----------------------------------------------------------------------------
# Detect OS + arch.
# ----------------------------------------------------------------------------
uname_s="$(uname -s 2>/dev/null || echo unknown)"
uname_m="$(uname -m 2>/dev/null || echo unknown)"
case "$uname_s" in
  Darwin) os="darwin" ;;
  Linux)  os="linux" ;;
  *) die "unsupported OS: $uname_s (supported: Darwin, Linux)" ;;
esac
# Normalise to bun's `--target=bun-<os>-<arch>` token, which is what
# build-and-publish.sh names the artefacts: `x64` (NOT `x86_64`) and
# `arm64`. Mapping uname's `x86_64`/`amd64` → `x64` here is REQUIRED —
# publishing as `-x64` while fetching `-x86_64` 404s on every Intel host.
case "$uname_m" in
  arm64|aarch64) arch="arm64" ;;
  x86_64|amd64)  arch="x64" ;;
  *) die "unsupported arch: $uname_m (supported: arm64, x86_64)" ;;
esac

# ----------------------------------------------------------------------------
# Proxy-bypass scoping (2026-07-27).
#
# Inside a fremforge CI job this script used to hang for ~129s and fail. The job
# environment sets `no_proxy` containing `frem.sh` so that git reaches the
# in-VPC clone-proxy directly — but proxy-bypass matching is by SUFFIX, so
# cli.frem.sh and trust.frem.sh match it too. They are public Bunny-fronted
# hosts with no direct route from the runner, so bypassing the proxy means the
# connection is simply dropped. Net effect: the documented one-liner
# `curl -sSfL https://cli.frem.sh/cli/install.sh | sh` did not work in our own CI.
#
# So for OUR hosts we scope the bypass list to loopback, which sends them
# through whatever proxy is configured — the correct route for an external host,
# including on a corporate proxy.
#
# Guarded on the hosts being the DEFAULTS. If someone points FREMFORGE_BIN_HOST
# or FREMFORGE_TRUST_HOST at an internal mirror, their `no_proxy` is very
# probably what makes that mirror reachable, and overriding it would break the
# air-gapped case to fix the CI one. In that case we touch nothing.
# ----------------------------------------------------------------------------
_scope_noproxy=0
if [ "$BIN_HOST" = "https://cli.frem.sh" ] && [ "$TRUST_HOST" = "https://trust.frem.sh" ]; then
  _scope_noproxy=1
fi

# Runs a command with the bypass list scoped to loopback, but only for the
# default public hosts. Wraps the download tool so curl and wget behave the same.
_run_fetch() {
  if [ "$_scope_noproxy" = "1" ]; then
    no_proxy="localhost,127.0.0.1" NO_PROXY="localhost,127.0.0.1" "$@"
  else
    "$@"
  fi
}

# ----------------------------------------------------------------------------
# Pick a download tool. curl preferred; fall back to wget.
# ----------------------------------------------------------------------------
if command -v curl >/dev/null 2>&1; then
  fetch() { _run_fetch curl -fsSL "$1" -o "$2"; }
elif command -v wget >/dev/null 2>&1; then
  fetch() { _run_fetch wget -q "$1" -O "$2"; }
else
  die "neither curl nor wget found in PATH"
fi

# ----------------------------------------------------------------------------
# Pick a SHA-256 checker. sha256sum (Linux), shasum -a 256 (macOS).
# ----------------------------------------------------------------------------
if [ "$SKIP_VERIFY" != "1" ]; then
  if command -v sha256sum >/dev/null 2>&1; then
    sha_check() {
      # sha256sum --check exits non-zero on any mismatch; --ignore-missing
      # so we only complain about the one file we care about.
      ( cd "$1" && sha256sum --check --ignore-missing "$2" >/dev/null 2>&1 )
    }
  elif command -v shasum >/dev/null 2>&1; then
    sha_check() {
      ( cd "$1" && shasum -a 256 --check --ignore-missing "$2" >/dev/null 2>&1 )
    }
  else
    die "neither sha256sum nor shasum found; install one or set FREMFORGE_SKIP_VERIFY=1 (NOT recommended)"
  fi
fi

# ----------------------------------------------------------------------------
# Build the URLs. The binary names match what build-and-publish.sh
# emits: fremforge-<os>-<arch> (no extension; no version suffix at the
# stable /cli/ path).
# ----------------------------------------------------------------------------
binary_name="fremforge-${os}-${arch}"
if [ "$VERSION" = "latest" ]; then
  binary_url="${BIN_HOST}/cli/${binary_name}"
  sums_url="${TRUST_HOST}/SHA256SUMS"
else
  binary_url="${BIN_HOST}/cli/v${VERSION}/${binary_name}"
  sums_url="${TRUST_HOST}/SHA256SUMS.v${VERSION}"
fi

log "detected ${os}-${arch}; installing ${VERSION}"
log "binary:  ${binary_url}"
log "sums:    ${sums_url}"

# ----------------------------------------------------------------------------
# Stage in a temp dir; verify; install.
# ----------------------------------------------------------------------------
tmp_dir="$(mktemp -d 2>/dev/null || mktemp -d -t fremforge)"
trap 'rm -rf "$tmp_dir"' EXIT

log "downloading binary..."
fetch "$binary_url" "${tmp_dir}/${binary_name}" || die "download failed: $binary_url"

if [ "$SKIP_VERIFY" = "1" ]; then
  log "WARNING: FREMFORGE_SKIP_VERIFY=1 — checksum verification disabled"
else
  log "downloading SHA256SUMS from canonical trust host..."
  fetch "$sums_url" "${tmp_dir}/SHA256SUMS" || die "SHA256SUMS download failed: $sums_url"

  log "verifying SHA-256..."
  if sha_check "$tmp_dir" "SHA256SUMS"; then
    log "checksum OK"
  else
    die "checksum verification FAILED — refusing to install. The binary at ${binary_url} does not match the hash published at ${sums_url}. This could be a corrupted download, a mid-flight modification, or a host compromise. Re-run; if it persists, mail security@frem.sh."
  fi
fi

chmod +x "${tmp_dir}/${binary_name}"

# ----------------------------------------------------------------------------
# Pick install dir. Prefer the env override; otherwise ~/.local/bin if
# it's on PATH; otherwise /usr/local/bin (with sudo if the user can
# sudo without password).
# ----------------------------------------------------------------------------
install_dir=""
if [ -n "${FREMFORGE_INSTALL_DIR:-}" ]; then
  install_dir="$FREMFORGE_INSTALL_DIR"
elif echo "${PATH:-}" | tr ':' '\n' | grep -qx "${HOME}/.local/bin" 2>/dev/null; then
  install_dir="${HOME}/.local/bin"
elif [ -w "/usr/local/bin" ]; then
  install_dir="/usr/local/bin"
else
  install_dir="${HOME}/.local/bin"
  log "neither /usr/local/bin nor \$HOME/.local/bin is on PATH; installing to ${install_dir} (add to PATH manually)"
fi

mkdir -p "$install_dir" || die "could not create install directory: $install_dir"

target="${install_dir}/fremforge"
if [ -w "$install_dir" ]; then
  mv "${tmp_dir}/${binary_name}" "$target"
elif command -v sudo >/dev/null 2>&1; then
  log "${install_dir} not writable; using sudo"
  sudo mv "${tmp_dir}/${binary_name}" "$target"
else
  die "${install_dir} not writable and sudo not available; set FREMFORGE_INSTALL_DIR to a writable path"
fi

log "installed to ${target}"

# ----------------------------------------------------------------------------
# Final verification + hint.
# ----------------------------------------------------------------------------
if [ -x "$target" ]; then
  log "run \`fremforge --help\` to get started, or \`fremforge whoami\` once \$FREMFORGE_TOKEN is set"
  if ! echo "${PATH:-}" | tr ':' '\n' | grep -qx "$install_dir" 2>/dev/null; then
    log "NOTE: ${install_dir} is not on PATH. Add this to your shell rc:"
    log "      export PATH=\"${install_dir}:\$PATH\""
  fi
else
  die "install completed but ${target} is not executable — check filesystem state"
fi
