#!/bin/sh
# Aiven Cloud CLI installer — https://get.aivencloud.io
#
#   curl -fsSL https://get.aivencloud.io | sh
#
# Detects OS/arch, downloads the matching `aivenc` release from this same
# host, verifies its SHA-256, and installs it under ~/.local/bin (no sudo).
# The sibling of tools/release/install.sh (the `px` installer) — the SAME
# hardened contract over the aivenc artifact namespace, laid out by
# tools/release/publish_aivenc.sh as:
#
#   /aivenc/CURRENT                                          immutable release id
#   /aivenc/releases/<id>/VERSION                            version + git rev
#   /aivenc/releases/<id>/bin/<target-triple>/VERSION        same release identity
#   /aivenc/releases/<id>/bin/<target-triple>/aivenc.tar.gz  the binary, tarred
#   /aivenc/releases/<id>/bin/<target-triple>/aivenc.sha256  "<hex>  aivenc.tar.gz"
#
# Overrides (mostly for testing / packaging):
#   AIVENC_DIST_BASE     alternate artifact host (default https://get.aivencloud.io)
#   AIVENC_INSTALL_DIR   alternate install dir   (default ~/.local/bin)
#
# POSIX sh on purpose: this must run on a stock macOS or minimal Linux box
# with nothing but curl/wget + tar + a shasum tool.
set -eu

base="${AIVENC_DIST_BASE:-https://get.aivencloud.io}"
install_dir="${AIVENC_INSTALL_DIR:-$HOME/.local/bin}"

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

# Read one canonical metadata record. Requiring exactly one newline-terminated
# line prevents a parser differential in which the installer trusts the first
# record while another verifier signs or displays the whole document. The byte
# equality also rejects NUL bytes that a shell variable cannot represent.
read_record() {
  record_file="$1"
  record_name="$2"
  record_max_bytes="$3"
  record_lines="$(LC_ALL=C wc -l < "$record_file" | tr -d '[:space:]')"
  [ "$record_lines" = 1 ] \
    || fail "$record_name must contain exactly one newline-terminated record"
  record_value="$(head -n1 "$record_file")"
  record_file_bytes="$(LC_ALL=C wc -c < "$record_file" | tr -d '[:space:]')"
  record_value_bytes="$(printf '%s' "$record_value" | LC_ALL=C wc -c | tr -d '[:space:]')"
  [ "$record_file_bytes" -eq $((record_value_bytes + 1)) ] \
    || fail "$record_name contains bytes outside its single canonical record"
  [ "$record_value_bytes" -le "$record_max_bytes" ] \
    || fail "$record_name is too long"
  printf '%s' "$record_value"
}

# --- 1. pick the target triple -------------------------------------------------
platform="${AIVENC_INSTALL_PLATFORM:-$(uname -s)/$(uname -m)}"
os="${platform%/*}"
arch="${platform#*/}"
case "$platform" in
  Darwin/arm64)          target="aarch64-apple-darwin" ;;
  Darwin/x86_64)         target="x86_64-apple-darwin" ;;
  Linux/x86_64)          target="x86_64-unknown-linux-musl" ;;
  Linux/aarch64)         target="aarch64-unknown-linux-musl" ;;
  *) fail "no prebuilt aivenc for $os/$arch yet — build from source: cargo build -p ac-cli (Rust >= 1.88)" ;;
esac

# --- 2. fetch ------------------------------------------------------------------
if command -v curl >/dev/null 2>&1; then
  fetch() { curl -fsSL "$1" -o "$2"; }
elif command -v wget >/dev/null 2>&1; then
  fetch() { wget -q "$1" -O "$2"; }
else
  fail "need curl or wget"
fi

tmp="$(mktemp -d)"
install_tmp=""
cleanup() {
  rm -rf "$tmp"
  [ -z "$install_tmp" ] || rm -f "$install_tmp"
}
trap cleanup EXIT INT TERM

fetch "$base/CURRENT" "$tmp/CURRENT" \
  || fail "download failed: $base/CURRENT (an atomic release pointer is required)"
release_id="$(read_record "$tmp/CURRENT" CURRENT 160)"
[ -n "$release_id" ] || fail "empty CURRENT — refusing an unidentified release"
case "$release_id" in
  [A-Za-z0-9]* ) ;;
  *) fail "invalid CURRENT release identity" ;;
esac
case "$release_id" in
  *[!A-Za-z0-9._-]*) fail "invalid CURRENT release identity" ;;
esac
release_base="$base/releases/$release_id"

fetch "$release_base/VERSION" "$tmp/release-VERSION" \
  || fail "download failed: $release_base/VERSION (release provenance is required)"
fetch "$release_base/bin/$target/VERSION" "$tmp/VERSION" \
  || fail "download failed: $release_base/bin/$target/VERSION (target provenance is required)"
# This value is presentation-only, but it came from the network: require a
# canonical printable record before displaying it. Empty provenance is a hard
# failure: a global version cannot authenticate which target was fetched.
version="$(read_record "$tmp/VERSION" 'target VERSION' 200)"
[ -n "$version" ] || fail "empty target VERSION — refusing an unidentified release"
version_printable="$(printf '%s' "$version" | LC_ALL=C tr -cd '[:print:]')"
[ "$version" = "$version_printable" ] \
  || fail "target VERSION contains non-printable bytes"
release_version="$(read_record "$tmp/release-VERSION" 'release VERSION' 200)"
[ -n "$release_version" ] || fail "empty release VERSION — refusing an unidentified release"
release_version_printable="$(printf '%s' "$release_version" | LC_ALL=C tr -cd '[:print:]')"
[ "$release_version" = "$release_version_printable" ] \
  || fail "release VERSION contains non-printable bytes"
[ "$version" = "$release_version" ] \
  || fail "target VERSION does not match its immutable release — refusing a mixed cut"

say "installing aivenc ($version, $target, release $release_id) from $base"
fetch "$release_base/bin/$target/aivenc.tar.gz" "$tmp/aivenc.tar.gz" \
  || fail "download failed: $release_base/bin/$target/aivenc.tar.gz (is this platform published yet?)"
fetch "$release_base/bin/$target/aivenc.sha256" "$tmp/aivenc.sha256" \
  || fail "download failed: $release_base/bin/$target/aivenc.sha256"

# --- 3. verify -----------------------------------------------------------------
want="$(awk '{print $1}' "$tmp/aivenc.sha256")"
if command -v sha256sum >/dev/null 2>&1; then
  got="$(sha256sum "$tmp/aivenc.tar.gz" | awk '{print $1}')"
elif command -v shasum >/dev/null 2>&1; then
  got="$(shasum -a 256 "$tmp/aivenc.tar.gz" | awk '{print $1}')"
else
  fail "need sha256sum or shasum to verify the download"
fi
if [ -z "$want" ] || [ "$want" != "$got" ]; then
  fail "checksum mismatch (want $want, got $got) — refusing to install"
fi

# --- 4. install ----------------------------------------------------------------
entries="$(tar -tzf "$tmp/aivenc.tar.gz")" \
  || fail "release archive is unreadable"
[ "$entries" = "aivenc" ] \
  || fail "release archive must contain exactly one entry named aivenc"
tar -xzf "$tmp/aivenc.tar.gz" -C "$tmp" aivenc
if [ ! -f "$tmp/aivenc" ] || [ -L "$tmp/aivenc" ]; then
  fail "release archive did not contain a regular aivenc binary"
fi
chmod +x "$tmp/aivenc"
"$tmp/aivenc" --version >/dev/null 2>&1 \
  || fail "downloaded aivenc cannot execute on $os/$arch — keeping the existing install"

mkdir -p "$install_dir"
# Copy into the destination filesystem, then replace with one same-filesystem
# rename. If download, verification, extraction, copy, or execution fails, an
# existing aivenc remains byte-for-byte untouched.
install_tmp="$(mktemp "$install_dir/.aivenc.install.XXXXXX")"
cp "$tmp/aivenc" "$install_tmp"
chmod +x "$install_tmp"
mv -f "$install_tmp" "$install_dir/aivenc"
install_tmp=""

say "installed: $install_dir/aivenc"
"$install_dir/aivenc" --version || true

case ":$PATH:" in
  *":$install_dir:"*) ;;
  *)
    say ""
    say "note: $install_dir is not on your PATH. Add it, e.g.:"
    say "  export PATH=\"$install_dir:\$PATH\""
    ;;
esac

say ""
say "next steps:"
say "  aivenc login           # sign in via the browser/SSO flow"
say "  aivenc whoami          # what this credential can do, active org/project"
say "  aivenc new             # create a sandbox (auto-provisions a project)"
say "  aivenc list            # sandboxes in the current context"
say ""
say "CI / automation: aivenc login --token '<api-key>' (or set AC_TOKEN)"
