#!/bin/sh
# loreva-agent bootstrap installer for Linux and macOS.
#
# Typical use (one-liner with a one-time token):
#   curl -fsSL https://get.loreva.dev | sh -s -- --token <one-time-token>
#
# Without a token: install only — operator runs `loreva-agent` later to
# link the node to a Loreva account interactively.
#
# Flags:
#   --token <token>     one-time token to link this node; if set, runs `setup` after install
#   --panel  <url>      override panel URL (default: $LOREVA_PANEL_URL)
#   --local  <path>     use a local binary instead of downloading
#   --version <ver>     specific release to download (default: latest)
#   --yes               skip Docker install prompt
#
# Env overrides:
#   LOREVA_PANEL_URL     default panel URL
#   LOREVA_RELEASE_BASE  base URL for release artifacts
#
# Exit codes: 1 generic, 2 unsupported OS/arch, 3 Docker required + declined.

set -eu

# Defaults injected at build time. Override via env or CLI flags.
LOREVA_PANEL_URL="${LOREVA_PANEL_URL:-https://portal.loreva.dev}"
LOREVA_RELEASE_BASE="${LOREVA_RELEASE_BASE:-https://get.loreva.dev/agent}"

# Token may come from --token flag, LOREVA_TOKEN env, or stdin via
# `echo $TOKEN | install.sh ... --token-stdin`. CLI arg is supported but
# discouraged: it shows up in `ps` and shell history.
token="${LOREVA_TOKEN:-}"
token_from_stdin=0
panel="$LOREVA_PANEL_URL"
local_bin=""
version="latest"
assume_yes=0

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

# --- arg parsing ----------------------------------------------------------

while [ $# -gt 0 ]; do
    case "$1" in
        --token)   shift; [ $# -gt 0 ] || die "--token requires value"; token="$1" ;;
        --token=*) token="${1#--token=}" ;;
        --token-stdin) token_from_stdin=1 ;;
        --panel)   shift; [ $# -gt 0 ] || die "--panel requires value"; panel="$1" ;;
        --panel=*) panel="${1#--panel=}" ;;
        --local)   shift; [ $# -gt 0 ] || die "--local requires value";  local_bin="$1" ;;
        --local=*) local_bin="${1#--local=}" ;;
        --version) shift; [ $# -gt 0 ] || die "--version requires value"; version="$1" ;;
        --version=*) version="${1#--version=}" ;;
        --yes|-y) assume_yes=1 ;;
        -h|--help)
            sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'
            exit 0
            ;;
        *) die "unknown argument: $1" ;;
    esac
    shift
done

# --- platform detection ---------------------------------------------------

detect_platform() {
    uname_s=$(uname -s)
    uname_m=$(uname -m)
    case "$uname_s" in
        Linux)  os="linux"  ;;
        Darwin) os="darwin" ;;
        *) die "unsupported OS: $uname_s (script supports linux, darwin)" ;;
    esac
    case "$uname_m" in
        x86_64|amd64)  arch="amd64" ;;
        aarch64|arm64) arch="arm64" ;;
        *) die "unsupported arch: $uname_m" ;;
    esac
    printf '%s/%s' "$os" "$arch"
}

require_cmd() {
    command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
}

# --- docker -----------------------------------------------------------------

docker_present() {
    command -v docker >/dev/null 2>&1
}

prompt_yes_no() {
    if [ "$assume_yes" = "1" ]; then return 0; fi
    printf '%s (y/N) ' "$1"
    read -r answer </dev/tty || answer=""
    case "$answer" in y|Y|yes|YES) return 0 ;; *) return 1 ;; esac
}

install_docker_linux() {
    log "Installing Docker via the official convenience script..."
    require_cmd curl
    curl -fsSL https://get.docker.com | sh
}

install_docker_darwin() {
    if command -v brew >/dev/null 2>&1; then
        log "Installing Docker Desktop via Homebrew..."
        brew install --cask docker
        die "Open Docker.app once to finish setup, then re-run this installer."
    fi
    die "Homebrew not found. Install Docker Desktop manually: https://docs.docker.com/desktop/install/mac/"
}

ensure_docker() {
    if docker_present; then
        # Silent — `loreva-agent install` prints "Found: docker ..." itself.
        # Printing here would duplicate the line in the operator's output.
        return 0
    fi
    log "Docker is not installed. Loreva Agent requires Docker."
    if ! prompt_yes_no "Install Docker now?"; then
        die "Docker is required. Install it manually and re-run."
    fi
    case "$1" in
        linux)  install_docker_linux  ;;
        darwin) install_docker_darwin ;;
    esac
}

# --- binary acquisition ---------------------------------------------------

resolve_version() {
    # When `latest`, query the latest.txt pointer on the release host.
    if [ "$version" != "latest" ]; then
        printf '%s' "$version"
        return
    fi
    require_cmd curl
    resolved=$(curl -fsSL "${LOREVA_RELEASE_BASE}/latest.txt" || true)
    if [ -z "$resolved" ]; then
        die "could not resolve 'latest' from ${LOREVA_RELEASE_BASE}/latest.txt"
    fi
    printf '%s' "$resolved"
}

download_binary() {
    platform="$1"; tmpdir="$2"
    os=$(printf '%s' "$platform" | cut -d/ -f1)
    arch=$(printf '%s' "$platform" | cut -d/ -f2)

    ver=$(resolve_version)
    # GoReleaser name_template is "loreva-agent_{Os}_{Arch}" — underscores.
    archive="loreva-agent_${os}_${arch}.tar.gz"
    url="${LOREVA_RELEASE_BASE}/${ver}/${archive}"

    log "Downloading: $url"
    require_cmd curl
    if ! curl -fSL -o "$tmpdir/$archive" "$url"; then
        die "download failed: $url
Pass --local <path> to bootstrap from a local binary instead."
    fi

    # Verify sha256 from checksums.txt sibling.
    sums_url="${LOREVA_RELEASE_BASE}/${ver}/checksums.txt"
    if curl -fsSL -o "$tmpdir/checksums.txt" "$sums_url"; then
        if command -v sha256sum >/dev/null 2>&1; then
            (cd "$tmpdir" && grep " ${archive}\$" checksums.txt | sha256sum -c -) \
                || die "checksum mismatch for ${archive}"
        elif command -v shasum >/dev/null 2>&1; then
            (cd "$tmpdir" && grep " ${archive}\$" checksums.txt | shasum -a 256 -c -) \
                || die "checksum mismatch for ${archive}"
        else
            warn "no sha256sum/shasum found — skipping checksum verification"
        fi
    else
        warn "checksums.txt not available — skipping verification"
    fi

    require_cmd tar
    tar -xzf "$tmpdir/$archive" -C "$tmpdir"
    printf '%s/loreva-agent' "$tmpdir"
}

# --- main flow ------------------------------------------------------------

main() {
    # Root gate. The bootstrap installer must register a real systemd /
    # launchd service and start it; both require root. Silently
    # downgrading to --user mode would either skip service registration
    # (incomplete install) or rely on `systemctl --user` + lingering
    # which the script cannot guarantee. Refuse early with a clear
    # next step instead — keeps the always-on contract honest.
    if [ "$(id -u)" -ne 0 ]; then
        die "This installer must run as root. Re-run with sudo:

  curl -fsSL https://get.loreva.dev | sudo sh

Or with a one-time token (env keeps it out of process argv):

  curl -fsSL https://get.loreva.dev | sudo LOREVA_TOKEN=<token> sh"
    fi

    platform=$(detect_platform)
    os=$(printf '%s' "$platform" | cut -d/ -f1)
    log "Platform: $platform"

    ensure_docker "$os"

    tmpdir=$(mktemp -d)
    trap 'rm -rf "$tmpdir"' EXIT

    if [ -n "$local_bin" ]; then
        log "Using local binary: $local_bin"
        [ -f "$local_bin" ] || die "--local file not found: $local_bin"
        cp "$local_bin" "$tmpdir/loreva-agent"
        chmod +x "$tmpdir/loreva-agent"
        binary="$tmpdir/loreva-agent"
    else
        binary=$(download_binary "$platform" "$tmpdir")
    fi

    log "Running post-install setup..."
    # Pass the panel URL through env so `loreva-agent install` seeds
    # config.yml with `panel.url` instead of relying on the operator to
    # edit the file later. `set -e` at the top makes a non-zero exit
    # from the binary abort the script — no silent half-install.
    LOREVA_PANEL_URL="$panel" "$binary" install

    if [ "$token_from_stdin" = "1" ]; then
        IFS= read -r token < /dev/stdin
        [ -n "$token" ] || die "--token-stdin set but no token on stdin"
    fi

    if [ -n "$token" ]; then
        log ""
        log "Linking node to $panel ..."
        # Token via env so it never appears in argv (visible in ps / shell
        # history). loreva-agent reads LOREVA_TOKEN automatically.
        LOREVA_TOKEN="$token" "$binary" setup
    fi
}

main "$@"
