#!/bin/sh
# spt installer (Linux) — served at the canonical Pages URL (ADR-0014):
#
#   curl -fsSL https://sabermage.github.io/spt-releases/install.sh | sh
#
# [impl->REQ-INSTALL-5] Non-interactive BY CONSTRUCTION: this same script is
# every adapter's pack-in on-demand install (no second mechanism), so it must
# never prompt. It downloads the latest release binary, sha256-checks it
# against the release's SHA256SUMS (full ed25519 verification is `spt update`'s
# job after first install; first-fetch trust = HTTPS + GitHub), places it under
# the per-OS install root, and registers the *user* PATH.
#
# Environment knobs (all optional):
#   SPT_INSTALL_DIR        install dir            (default: $HOME/.local/bin)
#   SPT_INSTALL_REPO       owner/repo             (default: SaberMage/spt-releases)
#   SPT_INSTALL_VERSION    release tag to pin     (default: latest)
#   SPT_INSTALL_ASSET_BASE URL or local dir holding the assets + SHA256SUMS
#                          directly (bypasses the release lookup; CI / air-gap)
#   SPT_INSTALL_NO_PATH    set to 1 to skip PATH registration
#   SPT_INSTALL_NO_SYMLINK set to 1 to skip the sudo-reachable symlink leg
#   SPT_INSTALL_NO_SERVICE set to 1 to skip the systemd user-service leg
#                          (CI keeps the E2E hermetic with these two)
set -eu

REPO="${SPT_INSTALL_REPO:-SaberMage/spt-releases}"
INSTALL_DIR="${SPT_INSTALL_DIR:-$HOME/.local/bin}"

die() { echo "spt-install: error: $*" >&2; exit 1; }

# ---- platform / arch -> release asset name -------------------------------
OS="$(uname -s)"
[ "$OS" = "Linux" ] || die "unsupported OS '$OS' (this script installs the Linux binary; Windows: install.ps1; macOS builds are not published yet)"
ARCH="$(uname -m)"
case "$ARCH" in
  x86_64|amd64) ASSET="spt-x86_64-linux" ;;
  *) die "no published build for architecture '$ARCH' yet (x86_64 only today)" ;;
esac

command -v curl >/dev/null 2>&1 || die "curl is required"
if command -v sha256sum >/dev/null 2>&1; then
  SHA256() { sha256sum "$1" | awk '{print $1}'; }
elif command -v shasum >/dev/null 2>&1; then
  SHA256() { shasum -a 256 "$1" | awk '{print $1}'; }
else
  die "need sha256sum or shasum to verify the download"
fi

WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT INT TERM

# ---- fetch: binary + SHA256SUMS ------------------------------------------
# [impl->REQ-INSTALL-1] the standalone one-line script half: latest-release
# lookup -> platform asset fetch -> sha256 verify -> place -> user PATH.
fetch() { # $1 = file name, $2 = dest path
  if [ -n "${SPT_INSTALL_ASSET_BASE:-}" ]; then
    case "$SPT_INSTALL_ASSET_BASE" in
      http://*|https://*) curl -fsSL "$SPT_INSTALL_ASSET_BASE/$1" -o "$2" ;;
      *) cp "$SPT_INSTALL_ASSET_BASE/$1" "$2" ;;
    esac
  elif [ -n "${SPT_INSTALL_VERSION:-}" ]; then
    curl -fsSL "https://github.com/$REPO/releases/download/$SPT_INSTALL_VERSION/$1" -o "$2"
  else
    curl -fsSL "https://github.com/$REPO/releases/latest/download/$1" -o "$2"
  fi
}

echo "spt-install: fetching $ASSET ..."
fetch "$ASSET" "$WORK/$ASSET"
fetch "SHA256SUMS" "$WORK/SHA256SUMS"

# ---- verify ----------------------------------------------------------------
WANT="$(awk -v a="$ASSET" '$2 == a { print $1 }' "$WORK/SHA256SUMS")"
[ -n "$WANT" ] || die "SHA256SUMS has no entry for $ASSET"
GOT="$(SHA256 "$WORK/$ASSET")"
[ "$GOT" = "$WANT" ] || die "sha256 mismatch for $ASSET (expected $WANT, got $GOT) — refusing to install"
echo "spt-install: sha256 verified."

# ---- place -----------------------------------------------------------------
# [impl->REQ-INSTALL-3] idempotent re-run: the binary is replaced atomically
# (rename over the old one); the PATH registration below is added at most once.
mkdir -p "$INSTALL_DIR"
chmod +x "$WORK/$ASSET"
mv -f "$WORK/$ASSET" "$INSTALL_DIR/spt"

# ---- user PATH registration -------------------------------------------------
PATH_NOTE=""
if [ "${SPT_INSTALL_NO_PATH:-0}" != "1" ]; then
  case ":$PATH:" in
    *":$INSTALL_DIR:"*) ;; # already reachable in this shell
    *)
      PROFILE="$HOME/.profile"
      MARK="# added by spt installer"
      if [ ! -f "$PROFILE" ] || ! grep -F "$MARK" "$PROFILE" >/dev/null 2>&1; then
        printf '\n%s\nexport PATH="%s:$PATH"\n' "$MARK" "$INSTALL_DIR" >> "$PROFILE"
        PATH_NOTE="Registered $INSTALL_DIR on your PATH via ~/.profile (takes effect in new login shells)."
      else
        PATH_NOTE="$INSTALL_DIR is registered in ~/.profile but not active in this shell."
      fi
      ;;
  esac
fi

# ---- sudo-reachable symlink (M8 decision 8, REQ-INSTALL-6) -------------------
# [impl->REQ-INSTALL-6] a user-scope install is invisible to sudo's
# secure_path, so bare `sudo spt` dies "command not found" (KNOWN-HAZARDS
# 5.10). Symlink the binary into /usr/local/bin when we can write there
# (an elevated install, or a permissive box); otherwise print the exact
# one-liner instead of prompting (non-interactive by construction).
SYMLINK_NOTE=""
if [ "${SPT_INSTALL_NO_SYMLINK:-0}" != "1" ]; then
  LINK_DIR="/usr/local/bin"
  if ln -sf "$INSTALL_DIR/spt" "$LINK_DIR/spt" 2>/dev/null; then
    SYMLINK_NOTE="Linked $LINK_DIR/spt -> $INSTALL_DIR/spt (sudo spt now resolves)."
  else
    SYMLINK_NOTE="Could not write $LINK_DIR (unelevated install). To make \`sudo spt\` resolve, run:
spt-install:   sudo ln -sf \"$INSTALL_DIR/spt\" $LINK_DIR/spt"
  fi
fi

# ---- systemd user service (M8 decision 17, REQ-INSTALL-8) ---------------------
# [impl->REQ-INSTALL-8] reboot-survivable daemon: a systemd USER unit (the
# daemon + its state stay in the user's universe — KNOWN-HAZARDS 5.7) plus
# enable-linger so it starts at boot, before any login. Linger needs root
# once; when this run is unelevated the exact command prints instead.
# Soft everywhere: a box without systemd (or without a user session bus)
# gets hints, never a failed install.
SERVICE_NOTE=""
if [ "${SPT_INSTALL_NO_SERVICE:-0}" != "1" ] && command -v systemctl >/dev/null 2>&1; then
  UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
  mkdir -p "$UNIT_DIR"
  # network-online ordering (REQ-DAEMON-9): the daemon's net endpoint needs the
  # network/DNS stack up — without this the autostart can beat it at boot and
  # come up net-less. Belt-and-suspenders only: the daemon also self-heals
  # (background net-bind retry), so a node recovers even where the user manager
  # never reaches network-online.target (common under linger).
  cat > "$UNIT_DIR/spt-daemon.service" <<UNIT
[Unit]
Description=spt-core per-machine daemon
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=$INSTALL_DIR/spt daemon run
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target
UNIT
  if systemctl --user daemon-reload 2>/dev/null \
     && systemctl --user enable --now spt-daemon.service 2>/dev/null; then
    SERVICE_NOTE="Registered + started the spt-daemon systemd user service."
  else
    SERVICE_NOTE="Wrote $UNIT_DIR/spt-daemon.service; could not enable it from here (no user session bus?). Enable with:
spt-install:   systemctl --user daemon-reload && systemctl --user enable --now spt-daemon"
  fi
  # Linger = start at boot without a login. Root-only; hint otherwise.
  LINGER_USER="${SUDO_USER:-$(id -un)}"
  if [ "$(id -u)" = "0" ] && command -v loginctl >/dev/null 2>&1; then
    if loginctl enable-linger "$LINGER_USER" 2>/dev/null; then
      SERVICE_NOTE="$SERVICE_NOTE
spt-install: Enabled linger for $LINGER_USER (daemon starts at boot, pre-login)."
    fi
  else
    SERVICE_NOTE="$SERVICE_NOTE
spt-install: For a pre-login boot start, run once: sudo loginctl enable-linger $LINGER_USER"
  fi
fi

# ---- report ----------------------------------------------------------------
# Print the absolute path: until PATH refreshes, invoke it absolutely.
echo "spt-install: installed $INSTALL_DIR/spt"
"$INSTALL_DIR/spt" --version
[ -z "$PATH_NOTE" ] || {
  echo "spt-install: $PATH_NOTE"
  echo "spt-install: in this shell, run it as $INSTALL_DIR/spt (or: export PATH=\"$INSTALL_DIR:\$PATH\")"
}
[ -z "$SYMLINK_NOTE" ] || echo "spt-install: $SYMLINK_NOTE"
[ -z "$SERVICE_NOTE" ] || echo "spt-install: $SERVICE_NOTE"
