#!/usr/bin/env sh
#
# Install the ERPyMe2 CLI.
#
#   curl -fsSL https://www.erpyme.mx/cli/install.sh | sh
#
# Options, as environment variables:
#   ERPYME_VERSION   a specific version instead of latest
#   ERPYME_PREFIX    where to install (default: ~/.erpyme, or /usr/local when root)
#   ERPYME_BASE_URL  where to fetch from (default: https://www.erpyme.mx/cli)
#
# POSIX sh, not bash: this is piped into whatever /bin/sh is on the machine.

set -eu

BASE_URL="${ERPYME_BASE_URL:-https://www.erpyme.mx/cli}"
VERSION="${ERPYME_VERSION:-latest}"

if [ "$(id -u)" = "0" ]; then
  PREFIX="${ERPYME_PREFIX:-/usr/local}"
else
  PREFIX="${ERPYME_PREFIX:-$HOME/.erpyme}"
fi

LIB_DIR="$PREFIX/lib/erpyme-cli"
BIN_DIR="$PREFIX/bin"

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

# ── preconditions, checked before anything is written ───────────────────────
#
# Each of these fails clearly now rather than leaving a half-installed tree
# that fails confusingly later.

command -v node >/dev/null 2>&1 || die "Node.js is required but was not found on PATH"

NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)"
if [ "$NODE_MAJOR" -lt 22 ]; then
  die "Node.js 22 or newer is required (found $(node -v)). The CLI uses fetch and the built-in test runner."
fi

if command -v curl >/dev/null 2>&1; then
  FETCH='curl -fsSL -o'
elif command -v wget >/dev/null 2>&1; then
  FETCH='wget -qO'
else
  die "curl or wget is required"
fi

command -v tar >/dev/null 2>&1 || die "tar is required"

TMP="$(mktemp -d)"
# Clean up on any exit, including a failed download — a half-extracted
# tarball in /tmp is the kind of thing that gets reused by the next run.
trap 'rm -rf "$TMP"' EXIT INT TERM

TARBALL="erpyme-cli-$VERSION.tgz"
say "Downloading $TARBALL from $BASE_URL"
# shellcheck disable=SC2086
$FETCH "$TMP/$TARBALL" "$BASE_URL/$TARBALL" || die "could not download $BASE_URL/$TARBALL"

# ── integrity ───────────────────────────────────────────────────────────────
#
# Verified when SHA256SUMS is published and a checksum tool exists, and SKIPPED
# LOUDLY otherwise. Silently skipping is how an unverified install looks
# identical to a verified one.
if command -v sha256sum >/dev/null 2>&1; then SHA_CMD="sha256sum"
elif command -v shasum >/dev/null 2>&1; then SHA_CMD="shasum -a 256"
else SHA_CMD=""
fi

if [ -n "$SHA_CMD" ] && ( # shellcheck disable=SC2086
  $FETCH "$TMP/SHA256SUMS" "$BASE_URL/SHA256SUMS" 2>/dev/null ); then
  EXPECTED="$(grep " $TARBALL\$" "$TMP/SHA256SUMS" | awk '{print $1}' || true)"
  if [ -n "$EXPECTED" ]; then
    ACTUAL="$(cd "$TMP" && $SHA_CMD "$TARBALL" | awk '{print $1}')"
    [ "$EXPECTED" = "$ACTUAL" ] || die "checksum mismatch for $TARBALL — refusing to install"
    say "Checksum verified"
  else
    say "WARNING: $TARBALL is not listed in SHA256SUMS; installing unverified"
  fi
else
  say "WARNING: could not verify the checksum; installing unverified"
fi

# ── install ─────────────────────────────────────────────────────────────────

mkdir -p "$TMP/x"
tar -xzf "$TMP/$TARBALL" -C "$TMP/x" || die "could not extract $TARBALL"
[ -f "$TMP/x/package/src/bin/erpyme.js" ] || die "archive does not look like the CLI"

# Validate the staged tree before replacing a working installation.
node "$TMP/x/package/src/bin/erpyme.js" catalog info --format json >/dev/null 2>&1 \
  || die "archive is incomplete; existing installation preserved"
if [ -d "$TMP/x/package/src/playbooks" ]; then
  node --input-type=module - "$TMP/x/package/vendor/dsl/src/parse.js" <<'JS' || die "archive has no usable playbook parser; existing installation preserved"
const { parse } = await import(process.argv[2]);
parse('emit 1\n');
JS
fi

mkdir -p "$LIB_DIR" "$BIN_DIR"
# Replace atomically-ish: move the old tree aside, put the new one in, then
# drop the old. An interrupted `rm -rf` of a live install leaves nothing.
if [ -d "$LIB_DIR.new" ]; then rm -rf "$LIB_DIR.new"; fi
cp -R "$TMP/x/package" "$LIB_DIR.new"
if [ -d "$LIB_DIR" ]; then rm -rf "$LIB_DIR.old"; mv "$LIB_DIR" "$LIB_DIR.old"; fi
mv "$LIB_DIR.new" "$LIB_DIR"
rm -rf "$LIB_DIR.old"

cat > "$BIN_DIR/erpyme" <<EOF
#!/usr/bin/env sh
exec node "$LIB_DIR/src/bin/erpyme.js" "\$@"
EOF
chmod +x "$BIN_DIR/erpyme"

# ── verify the thing that was just installed actually runs ──────────────────
#
# Not "files were copied". A tarball missing a vendored dependency copies
# perfectly and fails on first use, which the person then reads as a bug in
# the tool rather than in the install.
if ! "$BIN_DIR/erpyme" catalog info --format json >/dev/null 2>&1; then
  die "installed to $LIB_DIR but 'erpyme catalog info' failed — the archive may be incomplete"
fi

INSTALLED="$(node -p "require('$LIB_DIR/package.json').version" 2>/dev/null || echo '?')"
say ""
say "erpyme $INSTALLED installed to $LIB_DIR"

case ":$PATH:" in
  *":$BIN_DIR:"*) say "Run: erpyme --help" ;;
  *)
    say ""
    say "$BIN_DIR is not on your PATH. Add it:"
    say "    export PATH=\"$BIN_DIR:\$PATH\""
    say ""
    say "Then: erpyme --help"
    ;;
esac

say ""
say "Next: erpyme login --server https://your-host/api"
