#!/usr/bin/env bash
#
# Helicarrier one-command installer (Linux).
#
#   curl -fsSL https://fly.helicarrier.xyz | sudo bash
#
# Sets up everything needed to run Helicarrier as a self-hosted PaaS:
#   • Docker            — the container runtime (installed if missing)
#   • Railpack          — the zero-config git builder (installed if missing)
#   • the `heli` binary — the control plane (downloaded to /usr/local/bin)
#   • a systemd service — auto-starts on boot, restarts on crash
#
# On first boot the bridge SELF-PROVISIONS the rest (a managed BuildKit daemon and
# a managed Caddy edge for HTTPS + domain routing + static serving), so after this
# script you just open the dashboard, create the operator account, and onboard
# customers — they sign up, deploy from GitHub, and connect domains.
set -euo pipefail

# Where the binary is served from (override with HELI_DOWNLOAD_BASE for a mirror).
DOWNLOAD_BASE="${HELI_DOWNLOAD_BASE:-https://fly.helicarrier.xyz}"
HOME_DIR="${HELICARRIER_HOME:-/var/lib/helicarrier}"
PORT="${HELICARRIER_PORT:-4310}"
BIN=/usr/local/bin/heli

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

[ "$(id -u)" = 0 ] || die "run as root (sudo)."
[ "$(uname -s)" = Linux ] || die "this installer targets Linux. On macOS, use it for local dev with Docker Desktop + a host Caddy."

case "$(uname -m)" in
  x86_64|amd64) ARCH=amd64 ;;
  aarch64|arm64) ARCH=arm64 ;;
  *) die "unsupported architecture: $(uname -m)" ;;
esac

# ── Docker ──────────────────────────────────────────────────────────────────
if ! command -v docker >/dev/null 2>&1; then
  say "Installing Docker..."
  curl -fsSL https://get.docker.com | sh
  systemctl enable --now docker
fi
docker info >/dev/null 2>&1 || die "Docker is installed but not running (start the daemon and re-run)."
ok "Docker ready"

# ── Railpack (zero-config builder) ──────────────────────────────────────────
if ! command -v railpack >/dev/null 2>&1 && [ ! -x "$HOME/.local/bin/railpack" ] && [ ! -x /usr/local/bin/railpack ]; then
  say "Installing Railpack..."
  curl -fsSL https://railpack.com/install.sh | bash
  # make it visible on the system PATH for the service
  [ -x "$HOME/.local/bin/railpack" ] && install -m 0755 "$HOME/.local/bin/railpack" /usr/local/bin/railpack || true
fi
ok "Railpack ready"

# ── heli binary ─────────────────────────────────────────────────────────────
say "Downloading the latest Helicarrier binary..."
URL="${DOWNLOAD_BASE}/bridge-linux-${ARCH}"
if curl -fsSL "$URL" -o "$BIN.tmp"; then
  chmod 0755 "$BIN.tmp"
  # Rename over the (possibly running) binary — atomic, and avoids ETXTBSY that a
  # copy-in-place would hit when re-running the installer to UPDATE a live box.
  mv -f "$BIN.tmp" "$BIN"
  ok "Installed heli → $BIN ($($BIN version 2>/dev/null || echo downloaded))"
else
  rm -f "$BIN.tmp"
  die "could not download $URL — check ${DOWNLOAD_BASE} is serving bridge-linux-${ARCH}, or build from source: 'go build -o $BIN ./cmd/bridge'."
fi

# ── data dir + systemd service ──────────────────────────────────────────────
mkdir -p "$HOME_DIR"
say "Installing the systemd service..."
cat >/etc/systemd/system/helicarrier.service <<EOF
[Unit]
Description=Helicarrier control plane
After=docker.service network-online.target
Wants=docker.service network-online.target

[Service]
Environment=HELICARRIER_HOME=${HOME_DIR}
Environment=HELICARRIER_PORT=${PORT}
ExecStart=${BIN}
Restart=always
RestartSec=3
# the bridge manages docker (BuildKit, Caddy, service containers)
SupplementaryGroups=docker

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable helicarrier >/dev/null 2>&1 || true
# `restart` starts it on a fresh box and picks up the new binary on an update re-run
# (plain `enable --now` would NOT restart an already-running service).
systemctl restart helicarrier
ok "Service started"

# ── done ────────────────────────────────────────────────────────────────────
echo
ok "Helicarrier is up. The bridge is now self-provisioning BuildKit + the Caddy edge."
echo
say "Open the dashboard:   http://$(hostname -I 2>/dev/null | awk '{print $1}'):${PORT}"
say "Watch it activate:    journalctl -u helicarrier -f   (look for the Preflight ✓ lines)"
echo
echo "Next: create your operator account, set a root domain + your Paystack/Polar keys in"
echo "Settings, turn on Cloud mode + public signup, and your customers can start deploying."
