#!/bin/sh
# install.sh — Install the unified Ralph CLI launcher
#
# Usage: curl -fsSL https://get.ralph.dropback.com/install.sh | sh
#
# Fetches the published manifest, selects the correct launcher binary,
# verifies the SHA-256 checksum, and installs to $RALPH_INSTALL_DIR
# (default /usr/local/bin). If that dir isn't writable: use passwordless
# sudo when available (CI / AMI bake), else fall back to ~/.local/bin
# (public curl | sh — no surprise sudo password prompt).

set -eu

BINARY_NAME="ralph"
INSTALL_DIR="${RALPH_INSTALL_DIR:-/usr/local/bin}"
DIST_URL="${RALPH_DISTRIBUTION_URL:-https://get.ralph.dropback.com}"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

info() { printf "${GREEN}[info]${NC} %s\n" "$1"; }
warn() { printf "${YELLOW}[warn]${NC} %s\n" "$1"; }
error() { printf "${RED}[error]${NC} %s\n" "$1" >&2; exit 1; }

detect_os() {
  case "$(uname -s)" in
    Darwin*) echo "darwin" ;;
    Linux*)  echo "linux" ;;
    *)       error "Unsupported operating system: $(uname -s)" ;;
  esac
}

detect_arch() {
  case "$(uname -m)" in
    x86_64|amd64)  echo "amd64" ;;
    arm64|aarch64) echo "arm64" ;;
    *)             error "Unsupported architecture: $(uname -m)" ;;
  esac
}

find_downloader() {
  if command -v curl >/dev/null 2>&1; then
    echo "curl"
  elif command -v wget >/dev/null 2>&1; then
    echo "wget"
  else
    error "Neither curl nor wget found. Please install one and retry."
  fi
}

download() {
  url="$1"
  dest="$2"
  downloader=$(find_downloader)

  if [ "$downloader" = "curl" ]; then
    curl -fsSL -o "$dest" "$url"
  else
    wget -qO "$dest" "$url"
  fi
}

resolve_url() {
  path="$1"
  case "$path" in
    http://*|https://*) printf "%s" "$path" ;;
    *) printf "%s/%s" "$(printf "%s" "$DIST_URL" | sed 's#/*$##')" "$(printf "%s" "$path" | sed 's#^/*##')" ;;
  esac
}

extract_top_level_value() {
  key="$1"
  file="$2"
  sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" "$file" | head -1
}

extract_section_value() {
  section="$1"
  key="$2"
  file="$3"
  awk -v section="\"$section\"" -v key="\"$key\"" '
    $0 ~ section"[[:space:]]*:" { in_section=1; next }
    in_section && /}/ { exit }
    in_section && $0 ~ key"[[:space:]]*:" {
      line=$0
      sub(/^.*:[[:space:]]*"/, "", line)
      sub(/".*$/, "", line)
      print line
      exit
    }
  ' "$file"
}

find_checksum() {
  filename="$1"
  checksums_file="$2"
  awk -v target="$filename" '$2 == target { print $1; exit }' "$checksums_file"
}

main() {
  info "Installing Ralph CLI..."

  os=$(detect_os)
  arch=$(detect_arch)
  platform="${os}-${arch}"
  info "Detected platform: ${platform}"

  tmpdir=$(mktemp -d)
  trap 'rm -rf "$tmpdir"' EXIT

  # AMI qualification bakes pass an explicit branch-built launcher artifact so
  # smoke tests exercise the merge commit under review, not the latest public
  # release from get.ralph.dropback.com. Public curl installs keep the manifest
  # + checksum path below.
  if [ -n "${RALPH_LOCAL_LAUNCHER_FILE:-}" ]; then
    [ -s "$RALPH_LOCAL_LAUNCHER_FILE" ] || error "RALPH_LOCAL_LAUNCHER_FILE does not point to a readable non-empty file: ${RALPH_LOCAL_LAUNCHER_FILE}"
    version="${RALPH_VERSION:-local}"
    launcher_name="ralph-${platform}"
    launcher_file="${tmpdir}/${launcher_name}"
    info "Installing local launcher artifact: ${RALPH_LOCAL_LAUNCHER_FILE}"
    cp "$RALPH_LOCAL_LAUNCHER_FILE" "$launcher_file" || error "Failed to stage local launcher artifact"
  # N15: when RALPH_VERSION is set, skip the manifest dance entirely
  # and pull the versioned binary directly from
  # releases/<version>/ralph-<platform>. The release pipeline publishes
  # those keys for every cut version, so the URL is stable. Empty/unset
  # → fetch the top-level manifest (latest) as before.
  elif [ -n "${RALPH_VERSION:-}" ]; then
    version="$RALPH_VERSION"
    info "Pinning to version: ${version} (via RALPH_VERSION)"
    launcher_name="ralph-${platform}"
    launcher_path="releases/${version}/${launcher_name}"
    checksums_path="releases/${version}/checksums.txt"
  else
    manifest_file="${tmpdir}/manifest.json"
    download "$(resolve_url "manifest.json")" "$manifest_file" || error "Failed to download manifest"

    version=$(extract_top_level_value "version" "$manifest_file")
    [ -n "$version" ] || error "Manifest did not contain a version"
    info "Latest version: ${version}"

    launcher_path=$(extract_section_value "launcher" "$platform" "$manifest_file")
    [ -n "$launcher_path" ] || error "Manifest did not contain a launcher for ${platform}"

    checksums_path=$(extract_top_level_value "checksums" "$manifest_file")
    [ -n "$checksums_path" ] || error "Manifest did not contain a checksums path"

    launcher_name=$(basename "$launcher_path")
  fi

  if [ -z "${launcher_file:-}" ]; then
    launcher_file="${tmpdir}/${launcher_name}"
    checksums_file="${tmpdir}/checksums.txt"

    info "Downloading ${launcher_name}..."
    download "$(resolve_url "$launcher_path")" "$launcher_file" || error "Failed to download launcher"
    download "$(resolve_url "$checksums_path")" "$checksums_file" || error "Failed to download checksums"

    info "Verifying checksum..."
    expected_checksum=$(find_checksum "$launcher_name" "$checksums_file")
    [ -n "$expected_checksum" ] || error "Checksum not found for ${launcher_name}"

    if command -v sha256sum >/dev/null 2>&1; then
      actual_checksum=$(sha256sum "$launcher_file" | awk '{print $1}')
    elif command -v shasum >/dev/null 2>&1; then
      actual_checksum=$(shasum -a 256 "$launcher_file" | awk '{print $1}')
    else
      error "Neither sha256sum nor shasum found — cannot verify binary integrity."
    fi

    [ "$expected_checksum" = "$actual_checksum" ] || error "Checksum mismatch! Expected: ${expected_checksum}, Got: ${actual_checksum}"
    info "Checksum verified"
  fi

  chmod +x "$launcher_file"

  # Use `install`, NEVER `cp`, to write the launcher into place. `cp` onto an
  # existing SYMLINK follows it and writes through to the link TARGET; `install`
  # unlinks the destination first (portable on Linux coreutils + macOS BSD) and
  # creates a fresh regular file. This is load-bearing: the ralph-base AMI bake
  # symlinks `/usr/local/bin/ralph -> /opt/ralph-cli/dist/bin.js` (the JS agent
  # bundle) and THEN runs this installer with RALPH_INSTALL_DIR=/usr/local/bin.
  # With `cp` the Go launcher ELF got written straight into bin.js, corrupting
  # the JS bundle — the bake stayed green (every smoke execs the now-valid Go
  # binary) but production `node /opt/ralph-cli/dist/bin.js` hit the ELF magic
  # bytes and every Ralph died ~6s in (ami-06f2cf0d4313ccfa0, 2026-06-05). A
  # laptop user with a `ralph` symlink would have its target clobbered too.
  if [ -w "$INSTALL_DIR" ] || [ "$(id -u)" -eq 0 ]; then
    install -m 0755 "$launcher_file" "${INSTALL_DIR}/${BINARY_NAME}"
    info "Installed to ${INSTALL_DIR}/${BINARY_NAME}"
  elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
    # INSTALL_DIR is a system path we can't write as this user, but
    # passwordless sudo is available — the CI / AMI-bake case: Packer runs
    # this installer as the unprivileged `ubuntu` user (NOPASSWD sudo) and
    # sets RALPH_INSTALL_DIR=/usr/local/bin. Honor the requested system dir
    # via sudo so `ralph` lands on the global PATH for every user (incl. the
    # runtime `ralph` user), instead of the per-user ~/.local/bin fallback
    # below — which is NOT on PATH and made the devbox-base bake's
    # `command -v ralph` smoke fail with exit 127 (silently shipping no AMI
    # for two weeks). Gated on `sudo -n` so a public `curl | sh` user WITHOUT
    # passwordless sudo never gets a surprise password prompt mid-pipe.
    sudo install -m 0755 "$launcher_file" "${INSTALL_DIR}/${BINARY_NAME}"
    info "Installed to ${INSTALL_DIR}/${BINARY_NAME} (via sudo)"
  else
    INSTALL_DIR="${HOME}/.local/bin"
    mkdir -p "$INSTALL_DIR"
    install -m 0755 "$launcher_file" "${INSTALL_DIR}/${BINARY_NAME}"
    info "Installed to ${INSTALL_DIR}/${BINARY_NAME}"

    case ":$PATH:" in
      *":${INSTALL_DIR}:"*) ;;
      *) warn "Add ${INSTALL_DIR} to your PATH: export PATH=\"\$PATH:${INSTALL_DIR}\"" ;;
    esac
  fi

  info "Ralph CLI ${version} installed successfully!"
  info "Run 'ralph login' to get started."
}

main "$@"
