#!/usr/bin/env sh
# NOVA installer — Linux and macOS.
#
#   curl -fsSL novachan.org/install.sh | sh
#
# What this does: detects your OS/arch, downloads the matching NOVA release archive
# (compiler + runtime + stdlib + a bundled, trimmed clang/lld toolchain) from GitHub
# Releases, verifies its SHA256 against the published checksums.txt, extracts it to
# ~/.nova, wires NOVA_HOME + PATH into your shell profile, and runs `nova setup`.
#
# This script is intentionally small and plain-text — read it before piping it into a
# shell if you'd rather not trust it blindly. Prefer not to run it at all? Every asset
# below has a direct download link on novachan.org/download.html.
#
# Asset naming contract (must match .github/workflows/release.yml):
#   nova-linux-x64.tar.xz, nova-linux-arm64.tar.xz, nova-macos-arm64.tar.xz, checksums.txt

set -eu

REPO="novachan/nova"
RELEASE_BASE="https://github.com/${REPO}/releases/latest/download"
INSTALL_DIR="${NOVA_HOME:-$HOME/.nova}"

log() { printf '%s\n' "$*"; }
die() { printf 'error: %s\n' "$*" >&2; exit 1; }

need_cmd() {
    command -v "$1" >/dev/null 2>&1 || die "required command '$1' not found. Please install it and re-run."
}

# ── Detect platform ──────────────────────────────────────────────────────────
os_name=$(uname -s)
arch_name=$(uname -m)

case "$os_name" in
    Linux)  platform="linux" ;;
    Darwin) platform="macos" ;;
    *) die "unsupported OS: $os_name (NOVA installers currently cover Linux and macOS; see novachan.org/download.html)" ;;
esac

case "$arch_name" in
    x86_64|amd64) arch="x64" ;;
    arm64|aarch64) arch="arm64" ;;
    *) die "unsupported architecture: $arch_name" ;;
esac

if [ "$platform" = "macos" ] && [ "$arch" = "x64" ]; then
    die "macOS Intel (x86_64) is not yet published — Apple Silicon (arm64) is available today. See novachan.org/download.html for status."
fi
if [ "$platform" = "linux" ] && [ "$arch" != "x64" ] && [ "$arch" != "arm64" ]; then
    die "unsupported Linux architecture: $arch_name"
fi

asset="nova-${platform}-${arch}.tar.xz"
log "Detected: ${platform}/${arch} -> ${asset}"

need_cmd curl
need_cmd tar
if ! command -v sha256sum >/dev/null 2>&1 && ! command -v shasum >/dev/null 2>&1; then
    die "neither sha256sum nor shasum found -- cannot verify download integrity"
fi

# ── Download ──────────────────────────────────────────────────────────────────
work_dir=$(mktemp -d)
trap 'rm -rf "$work_dir"' EXIT INT TERM

log "Downloading ${asset}..."
curl -fsSL "${RELEASE_BASE}/${asset}" -o "${work_dir}/${asset}" \
    || die "download failed. Check your connection, or grab the archive directly from novachan.org/download.html"

log "Downloading checksums.txt..."
curl -fsSL "${RELEASE_BASE}/checksums.txt" -o "${work_dir}/checksums.txt" \
    || die "checksum download failed -- refusing to install an unverified archive"

# ── Verify ────────────────────────────────────────────────────────────────────
# Filter to just this asset's line, then hand it to sha256sum/shasum's own -c/--check
# parser rather than hand-parsing the checksum-file format (its exact spacing/marker
# conventions -- "*name" for binary mode, "  name" for text mode -- vary by platform
# and are easy to get subtly wrong with a hand-rolled grep/awk pattern).
checksum_line=$(grep -F "$asset" "${work_dir}/checksums.txt" || true)
[ -n "$checksum_line" ] || die "no checksum entry found for ${asset} in checksums.txt"

(
    cd "$work_dir"
    if command -v sha256sum >/dev/null 2>&1; then
        echo "$checksum_line" | sha256sum -c - >/dev/null
    elif command -v shasum >/dev/null 2>&1; then
        echo "$checksum_line" | shasum -a 256 -c - >/dev/null
    else
        die "neither sha256sum nor shasum found -- cannot verify download integrity"
    fi
) || die "checksum verification FAILED for ${asset}. This can mean a corrupted download or a tampered release -- do not proceed. Try again, and if it persists, report it at https://github.com/${REPO}/issues"
log "Checksum verified."

# ── Install ───────────────────────────────────────────────────────────────────
if [ -d "$INSTALL_DIR" ]; then
    log "Existing install found at ${INSTALL_DIR} -- upgrading in place."
fi
mkdir -p "$INSTALL_DIR"
log "Extracting to ${INSTALL_DIR}..."
tar -xJf "${work_dir}/${asset}" -C "$INSTALL_DIR" --strip-components=1

[ -x "${INSTALL_DIR}/bin/nova" ] || die "extracted archive did not contain bin/nova -- installation is corrupt"

# ── Wire up the shell profile ────────────────────────────────────────────────
shell_name=$(basename "${SHELL:-sh}")
case "$shell_name" in
    zsh)  profile="$HOME/.zshrc" ;;
    bash) profile="$HOME/.bashrc" ;;
    *)    profile="$HOME/.profile" ;;
esac

marker_start="# >>> nova installer >>>"
marker_end="# <<< nova installer <<<"
block="${marker_start}
export NOVA_HOME=\"${INSTALL_DIR}\"
export PATH=\"\$NOVA_HOME/bin:\$PATH\"
${marker_end}"

if [ -f "$profile" ] && grep -qF "$marker_start" "$profile" 2>/dev/null; then
    log "Updating existing NOVA block in ${profile}..."
    awk -v block="$block" '
        BEGIN { skip=0 }
        $0 == "# >>> nova installer >>>" { print block; skip=1; next }
        $0 == "# <<< nova installer <<<" { skip=0; next }
        skip == 0 { print }
    ' "$profile" > "${profile}.nova_tmp" && mv "${profile}.nova_tmp" "$profile"
else
    log "Adding NOVA_HOME/PATH to ${profile}..."
    printf '\n%s\n' "$block" >> "$profile"
fi

# ── Warm the build cache for this session too ────────────────────────────────
export NOVA_HOME="$INSTALL_DIR"
export PATH="$NOVA_HOME/bin:$PATH"
log "Running nova setup (one-time build-cache warmup)..."
"${INSTALL_DIR}/bin/nova" setup || log "warning: nova setup failed -- builds will still work, just slower on first run"

log ""
log "NOVA installed to ${INSTALL_DIR}"
log "Restart your shell, or run:  source ${profile}"
log "Then verify with:  nova version  &&  nova toolchain status"
