#!/usr/bin/env bash
#
#  Scalara agent installer
#  --------------------------------------------------------------------------
#  Install:
#    curl -sSL https://install.scalara.app | sudo bash
#
#  Non-interactive (automation):
#    SCALARA_API_KEY=scla_pk_... SCALARA_SECRET=scla_sk_... \
#      curl -sSL https://install.scalara.app | sudo bash
#
#  Uninstall:
#    SCALARA_UNINSTALL=1 curl -sSL https://install.scalara.app | sudo bash
#  --------------------------------------------------------------------------
set -euo pipefail

INGEST_URL="${SCALARA_INGEST_URL:-https://ingest.scalara.app}"
FALLBACK_URL="${SCALARA_FALLBACK_URL:-}"
RELEASE_BASE="https://pub-acb31dafb885401cb8998c437b7478f7.r2.dev"
RELEASE_PUBKEY=""
CONFIG_DIR="/etc/scalara"
CONFIG_FILE="${CONFIG_DIR}/agent.yaml"
STATE_DIR="/var/lib/scalara"
SPOOL_DIR="${STATE_DIR}/spool"
SERVICE_NAME="scalara-agent"
BIN_PATH="/usr/local/bin/scalara-agent"
AGENT_USER="scalara"

say()  { printf '\033[0;36m→\033[0m %s\n' "$1"; }
ok()   { printf '\033[0;32m✓\033[0m %s\n' "$1"; }
die()  { printf '\033[0;31m✗\033[0m %s\n' "$1" >&2; exit 1; }

# ── Preconditions ──────────────────────────────────────────────────────────
[ "$(id -u)" -eq 0 ] || die "Please run as root (use sudo)."

# ── Uninstall path (works regardless of release state) ─────────────────────
if [ "${SCALARA_UNINSTALL:-0}" = "1" ]; then
  printf '\n\033[1mRemoving Scalara agent\033[0m\n\n'
  systemctl disable --now "$SERVICE_NAME" >/dev/null 2>&1 || true
  rm -f "/etc/systemd/system/${SERVICE_NAME}.service"
  systemctl daemon-reload >/dev/null 2>&1 || true
  rm -f "$BIN_PATH"
  rm -rf "$CONFIG_DIR" "$STATE_DIR"
  userdel "$AGENT_USER" >/dev/null 2>&1 || true
  ok "Scalara agent, config, spool, and service user removed."
  exit 0
fi

printf '\n\033[1mScalara Agent installer\033[0m\n\n'

# Detect OS + arch (used for the correct binary + service manager).
OS="unknown"; [ -r /etc/os-release ] && . /etc/os-release && OS="${ID:-unknown}"
UNAME_M="$(uname -m)"
case "$UNAME_M" in
  x86_64|amd64) ARCH="amd64" ;;
  aarch64|arm64) ARCH="arm64" ;;
  *) die "Unsupported architecture: $UNAME_M" ;;
esac
command -v systemctl >/dev/null 2>&1 || die "systemd is required (systemctl not found)."
command -v curl >/dev/null 2>&1 || die "curl is required."
command -v sha256sum >/dev/null 2>&1 || die "sha256sum is required."
say "Detected: ${OS} (${ARCH})"

# ── Release guard ──────────────────────────────────────────────────────────
if [ -z "$RELEASE_BASE" ]; then
  printf '\n\033[1;33mScalara agent is not published for install yet.\033[0m\n'
  echo "You're early — the installer endpoint is live, but the agent binary"
  echo "release isn't available on this environment yet. Nothing was changed."
  echo
  echo "Track progress in your Scalara dashboard. No action needed."
  exit 0
fi

# ── Credentials ────────────────────────────────────────────────────────────
API_KEY="${SCALARA_API_KEY:-}"
SECRET="${SCALARA_SECRET:-}"
if [ -z "$API_KEY" ]; then
  printf 'Enter your Scalara API key (scla_pk_...): '; read -r API_KEY </dev/tty
fi
if [ -z "$SECRET" ]; then
  printf 'Enter your Scalara secret (scla_sk_...):  '; read -rs SECRET </dev/tty; echo
fi
[ -n "$API_KEY" ] && [ -n "$SECRET" ] || die "API key and secret are both required."

# ── Download the binary + verify integrity BEFORE it ever runs ─────────────
BIN_URL="${RELEASE_BASE%/}/latest/scalara-agent-linux-${ARCH}"
SUM_URL="${BIN_URL}.sha256"
SIG_URL="${BIN_URL}.minisig"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT

say "Downloading agent…"
curl -fsSL "$BIN_URL" -o "$TMP/scalara-agent" || die "Download failed: $BIN_URL"

# Checksum is mandatory: refuse to install anything we can't verify.
curl -fsSL "$SUM_URL" -o "$TMP/scalara-agent.sha256" \
  || die "Could not fetch checksum — refusing to install."
( cd "$TMP" && printf '%s  scalara-agent\n' "$(cat scalara-agent.sha256)" | sha256sum -c - >/dev/null ) \
  || die "Checksum verification FAILED — the binary was tampered with or corrupted. Refusing to install."
ok "Checksum verified"

# Signature (strongest): when a release public key is configured it is REQUIRED,
# which also defeats a tampered checksum (an attacker cannot forge the signature).
if [ -n "$RELEASE_PUBKEY" ]; then
  command -v minisign >/dev/null 2>&1 \
    || die "Signature verification is required but 'minisign' is not installed (e.g. apt-get install minisign)."
  curl -fsSL "$SIG_URL" -o "$TMP/scalara-agent.minisig" \
    || die "Could not fetch signature — refusing to install."
  printf '%s\n' "$RELEASE_PUBKEY" > "$TMP/scalara.pub"
  minisign -Vm "$TMP/scalara-agent" -p "$TMP/scalara.pub" -x "$TMP/scalara-agent.minisig" >/dev/null 2>&1 \
    || die "Signature verification FAILED — refusing to install."
  ok "Signature verified"
fi

# ── Install user, binary, config, service ──────────────────────────────────
id -u "$AGENT_USER" >/dev/null 2>&1 \
  || useradd --system --no-create-home --shell /usr/sbin/nologin "$AGENT_USER"
install -m 0755 "$TMP/scalara-agent" "$BIN_PATH"

mkdir -p "$CONFIG_DIR"
umask 077
# These keys match the Go agent's config schema EXACTLY (agent/internal/config).
cat > "$CONFIG_FILE" <<EOF
api_key: "${API_KEY}"
secret: "${SECRET}"
endpoint: "${INGEST_URL}"
fallback_endpoint: "${FALLBACK_URL}"
# Live cadence: collect every 5s, flush every 10s (≈2 samples/batch). Each flush
# is a tiny gzipped request, so this stays cheap and horizontally scalable (the
# intake is a stateless edge Worker) while the dashboard updates in ~10-15s.
collect_interval: 5s
flush_interval: 10s
process_interval: 20s
http_timeout: 30s
# Bounded buffers so the agent can never destabilise this server. Unsent
# telemetry spills from the in-memory ring to the on-disk spool; both are capped.
buffer_max_samples: 10000
spool_dir: "${SPOOL_DIR}"
spool_max_bytes: 104857600
process_top_n: 10
# To collect logs, add allowlisted file paths, e.g.:
# logs:
#   - /var/log/nginx/error.log
EOF
chmod 0600 "$CONFIG_FILE"
chown -R "$AGENT_USER":"$AGENT_USER" "$CONFIG_DIR"
ok "Wrote config to $CONFIG_FILE"

mkdir -p "$STATE_DIR"
chown -R "$AGENT_USER":"$AGENT_USER" "$STATE_DIR"

cat > "/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=Scalara monitoring agent
Documentation=https://scalara.app/docs
After=network-online.target
Wants=network-online.target
# systemd's default start limit (5 restarts / 10s) makes it PERMANENTLY give up on
# a flapping service. That would leave the agent dead until a human intervened, so
# the limit is disabled: it must always keep trying to come back.
StartLimitIntervalSec=0

[Service]
Type=simple
User=${AGENT_USER}
ExecStart=${BIN_PATH} -config ${CONFIG_FILE}
Restart=always
RestartSec=5
# Give the agent a moment to flush its buffer and send its shutdown beacon, so a
# planned reboot is recorded as intentional instead of raising a false incident.
KillSignal=SIGTERM
TimeoutStopSec=10

# Resource ceilings: if our own code ever misbehaves, the kernel kills THIS
# process and systemd restarts it — the customer's server is never the casualty.
MemoryMax=192M
CPUQuota=15%
# Keep the Go runtime collecting aggressively well before the hard cap is hit.
Environment=GOMEMLIMIT=128MiB

# Least privilege: the agent only reads host metrics; it needs no write access
# beyond its own state directory (spool + machine id).
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
ReadWritePaths=${STATE_DIR}

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now "$SERVICE_NAME" >/dev/null 2>&1
ok "Installed and started ${SERVICE_NAME}"

# ── Verify connection ──────────────────────────────────────────────────────
if [ -n "$INGEST_URL" ]; then
  say "Verifying connection to Scalara…"
  if curl -fsS -X POST "${INGEST_URL%/}/v1/verify" \
        -H "X-Scalara-Key: ${API_KEY}" \
        -H "Authorization: Bearer ${SECRET}" >/dev/null 2>&1; then
    ok "Connected"
  else
    echo "  (could not verify yet — the agent will keep retrying in the background)"
  fi
fi

printf '\n\033[0;32m✅ Done.\033[0m This server will appear in your Scalara dashboard shortly.\n'
printf 'Manage the service:  systemctl status %s   ·   journalctl -u %s -f\n\n' "$SERVICE_NAME" "$SERVICE_NAME"
