#!/bin/sh
# install.sh — one-command installer for the Soft Machine compute daemon (`deamond`).
#
#   curl -fsSL https://dl.soft-machine.io/install.sh | sh
#
# Detects the host arch, downloads the matching static-musl `deamond` binary, verifies
# its sha256, and installs it to /usr/local/bin. With an enrollment token in the
# environment it also drives the headless setup→enroll→enable flow, so a single line
# takes a fresh Linux box from nothing to an enrolled, workspace-serving daemon:
#
#   curl -fsSL https://dl.soft-machine.io/install.sh | DEAMON_ENROLL_TOKEN=sm_enroll_… sh
#
# POSIX sh on purpose (no bash-isms): minimal hosts and container base images often ship
# only /bin/sh. Fail-closed: any download, checksum, or install error aborts non-zero and
# leaves nothing half-installed.
#
# Tunables (environment):
#   DEAMON_BASE_URL     download host           (default https://dl.soft-machine.io)
#   DEAMON_VERSION      release to fetch        (default "latest")
#   DEAMON_INSTALL_DIR  install prefix          (default /usr/local/bin)
#   DEAMON_ENROLL_TOKEN single-use sm_enroll_…  (if set → run headless setup+enroll)
#   DEAMON_MODE         userspace | kernel      (default userspace; only with a token)
#   DEAMON_RELAY_URL    relay to dial           (ws://|wss://; default = production relay)
#
# Honest scope: this fetches the RAW signed musl binary + its sha256 (the demo/quickstart
# path). The hardened distribution wraps the same bytes in the `smpack` envelope verified
# by `smpack verify` / `deamond doctor` (docs/install.md §2.1); that is the production
# supply-chain path, not this bootstrap.

set -eu

DEAMON_BASE_URL="${DEAMON_BASE_URL:-https://dl.soft-machine.io}"
DEAMON_VERSION="${DEAMON_VERSION:-latest}"
DEAMON_INSTALL_DIR="${DEAMON_INSTALL_DIR:-/usr/local/bin}"
DEAMON_MODE="${DEAMON_MODE:-userspace}"
BIN_NAME="deamond"

log()  { printf '\033[36m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[33mwarning:\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }

# Run a command as root: directly if we are root, via sudo otherwise. A box with no sudo
# and a non-root user can't install to a system prefix — say so plainly.
as_root() {
  if [ "$(id -u)" -eq 0 ]; then
    "$@"
  elif command -v sudo >/dev/null 2>&1; then
    sudo "$@"
  else
    die "need root (or sudo) to run: $*"
  fi
}

# Map uname to the shipped target triple. Linux ships the static-musl artifact; macOS
# ships the native aarch64/x86_64-apple-darwin binary. Both run the daemon — on macOS via
# the process backend with NO isolation (cgroups/namespaces/KVM are Linux-only); the
# preflight + `deamond status` report that honestly.
#
# Windows is intentionally out of scope for this POSIX-sh script: it needs a separate
# PowerShell installer (download + checksum + SCM/Task-Scheduler registration), tracked
# separately. This script never pretends to support it.
#
# `DEAMON_TARGET` is an explicit override (advanced hosts / CI): set it and we trust
# you, skipping the OS/arch probe entirely.
detect_target() {
  if [ -n "${DEAMON_TARGET:-}" ]; then
    echo "$DEAMON_TARGET"
    return 0
  fi
  os="$(uname -s)"
  arch="$(uname -m)"
  case "$os" in
    Linux)
      case "$arch" in
        x86_64 | amd64)  echo "x86_64-unknown-linux-musl" ;;
        aarch64 | arm64) echo "aarch64-unknown-linux-musl" ;;
        *) die "unsupported architecture: ${arch} (deamond ships x86_64 and aarch64 only)" ;;
      esac
      ;;
    Darwin)
      case "$arch" in
        arm64 | aarch64) echo "aarch64-apple-darwin" ;;
        x86_64 | amd64)  echo "x86_64-apple-darwin" ;;
        *) die "unsupported architecture: ${arch} (deamond ships x86_64 and aarch64 only)" ;;
      esac
      ;;
    *) die "unsupported OS: ${os} (deamond ships Linux + macOS; Windows needs the \
PowerShell installer)" ;;
  esac
}

# Download $1 → $2 using whichever fetcher is present, failing on HTTP errors. An https
# URL is pinned to TLS (`--proto =https`, no silent downgrade to a MITM's http); a plain
# http base is allowed only because someone explicitly opted into it (local mirror / dev),
# and we say so out loud.
fetch() {
  url="$1"; dest="$2"
  case "$url" in
    https://*) scheme_https=1 ;;
    http://*)  scheme_https=0; warn "downloading over plaintext http (no TLS): ${url}" ;;
    *) die "unsupported URL scheme (need http/https): ${url}" ;;
  esac
  if command -v curl >/dev/null 2>&1; then
    if [ "$scheme_https" -eq 1 ]; then
      curl -fsSL --proto '=https' --tlsv1.2 -o "$dest" "$url"
    else
      curl -fsSL -o "$dest" "$url"
    fi
  elif command -v wget >/dev/null 2>&1; then
    wget -q -O "$dest" "$url"
  else
    die "need curl or wget to download ${url}"
  fi
}

# Portable sha256 of $1 → hex on stdout (coreutils or BSD/macOS).
sha256_of() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$1" | awk '{print $1}'
  else
    die "no sha256 tool (sha256sum / shasum) on PATH — cannot verify the download"
  fi
}

main() {
  target="$(detect_target)"
  base="${DEAMON_BASE_URL}/${DEAMON_VERSION}"
  artifact="${BIN_NAME}-${target}"
  log "installing ${BIN_NAME} (${target}) from ${base}"

  tmp="$(mktemp -d "${TMPDIR:-/tmp}/deamond-install.XXXXXX")"
  # Clean up the scratch dir on any exit, success or failure.
  trap 'rm -rf "$tmp"' EXIT INT TERM

  log "downloading binary + checksum"
  fetch "${base}/${artifact}" "${tmp}/${BIN_NAME}"
  fetch "${base}/${artifact}.sha256" "${tmp}/${BIN_NAME}.sha256"

  # The .sha256 is the coreutils `<hex>  <name>` shape; take the first field and compare
  # against what we actually downloaded. A mismatch is a hard stop — never run unverified
  # bytes we're about to grant root.
  want="$(awk '{print $1}' "${tmp}/${BIN_NAME}.sha256")"
  got="$(sha256_of "${tmp}/${BIN_NAME}")"
  [ -n "$want" ] || die "empty checksum file from ${base}/${artifact}.sha256"
  if [ "$want" != "$got" ]; then
    die "checksum mismatch for ${artifact}: expected ${want}, got ${got}"
  fi
  log "checksum verified (${got})"

  chmod 0755 "${tmp}/${BIN_NAME}"
  log "installing to ${DEAMON_INSTALL_DIR}/${BIN_NAME}"
  as_root mkdir -p "$DEAMON_INSTALL_DIR"
  as_root install -m 0755 "${tmp}/${BIN_NAME}" "${DEAMON_INSTALL_DIR}/${BIN_NAME}"

  installed="${DEAMON_INSTALL_DIR}/${BIN_NAME}"
  log "installed: $("$installed" --version 2>/dev/null || echo "$installed")"

  if [ -n "${DEAMON_ENROLL_TOKEN:-}" ]; then
    # Headless quickstart: setup writes+validates config, enroll burns the token and
    # binds the org, then the service comes up. Each step is privileged; we narrate it.
    log "enrolling headlessly (mode=${DEAMON_MODE})"
    # Optional relay override (self-hosted / staging control plane). Quote-safe: build the
    # argv with set -- so an unset relay simply omits the flag.
    set -- setup --yes --mode "$DEAMON_MODE" --token "$DEAMON_ENROLL_TOKEN"
    [ -n "${DEAMON_RELAY_URL:-}" ] && set -- "$@" --relay-url "$DEAMON_RELAY_URL"
    as_root "$installed" "$@"
    as_root "$installed" enroll --token "$DEAMON_ENROLL_TOKEN"
    if command -v systemctl >/dev/null 2>&1; then
      as_root systemctl enable --now deamond.service
      log "deamond.service enabled and started"
    elif [ "$(uname -s)" = "Darwin" ]; then
      # macOS: the daemon ships a launchd manager (RunAtLoad + KeepAlive). The packaged
      # installer registers the plist; this bootstrap leaves it to `deamond` so we don't
      # write into LaunchDaemons from a curl|sh. Tell the operator how to bring it up.
      warn "macOS: no systemd. supervise via launchd, or run '${installed} run' yourself"
    else
      warn "no systemd; supervise '${installed} run' yourself"
    fi
    log "done — your daemon is enrolled and serving. Check it with: ${BIN_NAME} status"
  else
    cat <<EOF

${BIN_NAME} is installed. Next:

  sudo ${BIN_NAME} setup            # interactive: preflight, link your org, pick a mode

  # ...or headless with a single-use enrollment token from the dashboard:
  sudo ${BIN_NAME} setup --yes --mode userspace --token sm_enroll_...
  sudo ${BIN_NAME} enroll --token sm_enroll_...
  sudo systemctl enable --now deamond.service

Docs: https://github.com/Soft-Machine-io/deamon/blob/main/docs/install.md
EOF
  fi
}

main "$@"
