#!/bin/sh
# Online installer for the Aevos `nabi` CLI. Published as https://aevos.io/install.sh.
#   curl -fsSL https://aevos.io/install.sh | sh
#
# This is rung 0 of the adoption ladder only: it fetches the latest release pointer, verifies the
# tarball sha256 against BOTH latest.json and the release's SHA256SUMS, extracts it, installs the
# `nabi` binary, and symlinks it onto PATH. It never touches ~/.config/nabi, never runs `nabi init`,
# never uses sudo, and never signs or restarts anything. See docs/section 2 of the ship front-door
# contract for the exact behavior contract this implements.
#
# Env overrides:
#   NABI_INSTALL_BASE_URL        default https://aevos.io (point at a staging mirror for testing)
#   NABI_INSTALL_VERSION         default: whatever latest.json names
#   NABI_INSTALL_DIR             default $HOME/.local/share/nabi/bin
#   NABI_INSTALL_BIN_LINK_DIR    default $HOME/.local/bin
#   NABI_INSTALL_NO_MODIFY_PATH  set to 1 to suppress the PATH hint
#   NABI_INSTALL_TRIPLE          override triple detection (testing an unsupported-triple path)
set -eu

NABI_INSTALL_BASE_URL="${NABI_INSTALL_BASE_URL:-https://aevos.io}"
NABI_INSTALL_VERSION="${NABI_INSTALL_VERSION:-}"
NABI_INSTALL_DIR="${NABI_INSTALL_DIR:-${HOME}/.local/share/nabi/bin}"
NABI_INSTALL_BIN_LINK_DIR="${NABI_INSTALL_BIN_LINK_DIR:-${HOME}/.local/bin}"
NABI_INSTALL_NO_MODIFY_PATH="${NABI_INSTALL_NO_MODIFY_PATH:-0}"

info() { printf 'install.sh: %s\n' "$1"; }
warn() { printf 'install.sh: warning: %s\n' "$1" >&2; }
fatal() { printf 'install.sh: error: %s\n' "$1" >&2; exit 1; }

need() { command -v "$1" >/dev/null 2>&1 || fatal "required tool '$1' not found"; }

# ---- sha256 (macOS ships shasum, Linux ships sha256sum) ---------------------------------------
sha256_file() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$1" | awk '{print $1}'
  else
    fatal "need sha256sum or shasum -a 256 to verify downloads"
  fi
}

# ---- downloader ---------------------------------------------------------------------------------
if command -v curl >/dev/null 2>&1; then
  fetch_to_file() { curl -fsSL -o "$2" "$1"; }
  fetch_to_stdout() { curl -fsSL "$1"; }
elif command -v wget >/dev/null 2>&1; then
  fetch_to_file() { wget -q -O "$2" "$1"; }
  fetch_to_stdout() { wget -qO- "$1"; }
else
  fatal "curl or wget is required"
fi

# ---- triple detection (reused/adapted from platform/install/install.sh's uname mapping) --------
detect_triple() {
  if [ -n "${NABI_INSTALL_TRIPLE:-}" ]; then
    printf '%s\n' "$NABI_INSTALL_TRIPLE"
    return 0
  fi
  _os="$(uname -s)"
  _arch="$(uname -m)"
  case "$_arch" in
    x86_64 | amd64) _arch="x86_64" ;;
    aarch64 | arm64) _arch="aarch64" ;;
    *) fatal "unsupported architecture: $_arch" ;;
  esac
  case "$_os" in
    Darwin) printf '%s-apple-darwin\n' "$_arch" ;;
    Linux) printf '%s-unknown-linux-gnu\n' "$_arch" ;;
    *) fatal "unsupported platform: $_os" ;;
  esac
}

# ---- tiny JSON field extraction (no jq dependency; fields are flat strings) --------------------
# Prints the string value of "<key>": "<value>" at any nesting depth (first match).
json_str_field() {
  key="$1"
  sed -n 's/.*"'"$key"'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1
}

main() {
  need mkdir
  need chmod
  need tar

  triple="$(detect_triple)"
  info "detected triple: $triple"

  work_dir="$(mktemp -d "${TMPDIR:-/tmp}/nabi-install.XXXXXX")"
  trap 'rm -rf "$work_dir"' EXIT

  latest_url="${NABI_INSTALL_BASE_URL}/releases/latest.json"
  info "fetching $latest_url"
  latest_json="$work_dir/latest.json"
  fetch_to_file "$latest_url" "$latest_json" || fatal "could not fetch $latest_url"

  schema="$(json_str_field schema <"$latest_json")"
  case "$schema" in
    aevos.release.latest.v1) ;;
    *) fatal "unexpected latest.json schema: '${schema:-missing}'" ;;
  esac

  version="${NABI_INSTALL_VERSION:-}"
  if [ -z "$version" ]; then
    version="$(json_str_field version <"$latest_json")"
  fi
  [ -n "$version" ] || fatal "could not determine a version to install"
  info "installing version $version"

  # Pull the artifact block for our triple: "<triple>":{"url":"...","sha256":"..."}
  # Isolate the single-line JSON fragment that starts at our triple key, then read url/sha256 from it.
  triple_fragment="$(tr -d '\n' <"$latest_json" | sed -n 's/.*"'"$triple"'"[[:space:]]*:[[:space:]]*{\([^}]*\)}.*/\1/p')"
  if [ -z "$triple_fragment" ]; then
    fatal "unsupported triple for this release: $triple (no artifact published for it)"
  fi
  artifact_url_path="$(printf '%s' "$triple_fragment" | json_str_field url)"
  artifact_sha_latest="$(printf '%s' "$triple_fragment" | json_str_field sha256)"
  [ -n "$artifact_url_path" ] || fatal "latest.json has no url for triple $triple"
  [ -n "$artifact_sha_latest" ] || fatal "latest.json has no sha256 for triple $triple"

  case "$artifact_url_path" in
    http://* | https://*) artifact_url="$artifact_url_path" ;;
    /*) artifact_url="${NABI_INSTALL_BASE_URL}${artifact_url_path}" ;;
    *) artifact_url="${NABI_INSTALL_BASE_URL}/${artifact_url_path}" ;;
  esac

  tarball_name="$(basename "$artifact_url_path")"
  tarball_path="$work_dir/$tarball_name"
  info "downloading $artifact_url"
  fetch_to_file "$artifact_url" "$tarball_path" || fatal "could not download $artifact_url"

  # Verify against latest.json's sha256.
  actual_sha="$(sha256_file "$tarball_path")"
  if [ "$actual_sha" != "$artifact_sha_latest" ]; then
    fatal "sha256 mismatch against latest.json for $tarball_name (expected $artifact_sha_latest, got $actual_sha)"
  fi

  # Verify again against the release's SHA256SUMS (belt + suspenders: two independent sources must agree).
  sums_url="${NABI_INSTALL_BASE_URL}/releases/${version}/SHA256SUMS"
  sums_path="$work_dir/SHA256SUMS"
  info "fetching $sums_url"
  if ! fetch_to_file "$sums_url" "$sums_path"; then
    fatal "could not fetch SHA256SUMS for $version"
  fi
  sums_expected="$(awk -v f="$tarball_name" '$2 == f || $2 == "*"f {print $1; exit}' "$sums_path")"
  [ -n "$sums_expected" ] || fatal "SHA256SUMS has no entry for $tarball_name"
  if [ "$sums_expected" != "$artifact_sha_latest" ]; then
    fatal "sha256 mismatch between latest.json and SHA256SUMS for $tarball_name; aborting"
  fi
  if [ "$actual_sha" != "$sums_expected" ]; then
    fatal "downloaded tarball does not match SHA256SUMS for $tarball_name; aborting (no install performed)"
  fi
  info "sha256 verified against latest.json and SHA256SUMS: $actual_sha"

  extract_dir="$work_dir/extracted"
  mkdir -p "$extract_dir"
  tar -xzf "$tarball_path" -C "$extract_dir" || fatal "could not extract $tarball_name"

  binary_path="$(find "$extract_dir" -type f -name nabi -perm -u+x 2>/dev/null | head -n 1)"
  if [ -z "$binary_path" ]; then
    binary_path="$(find "$extract_dir" -type f -name nabi 2>/dev/null | head -n 1)"
  fi
  [ -n "$binary_path" ] && [ -f "$binary_path" ] || fatal "tarball did not contain a 'nabi' binary"

  mkdir -p "$NABI_INSTALL_DIR"
  # Atomic install: stage into the target dir, chmod, then rename over the final name.
  staged_path="$(mktemp "$NABI_INSTALL_DIR/.nabi.XXXXXX")"
  cp "$binary_path" "$staged_path"
  chmod 0755 "$staged_path"
  final_path="$NABI_INSTALL_DIR/nabi"
  mv -f "$staged_path" "$final_path"
  info "installed $final_path"

  if ! "$final_path" --version >/dev/null 2>&1; then
    warn "installed binary did not report --version cleanly; it may not run on this host"
  fi

  if [ -n "$NABI_INSTALL_BIN_LINK_DIR" ]; then
    mkdir -p "$NABI_INSTALL_BIN_LINK_DIR"
    ln -sfn "$final_path" "$NABI_INSTALL_BIN_LINK_DIR/nabi"
    info "symlinked $NABI_INSTALL_BIN_LINK_DIR/nabi -> $final_path"
  fi

  if [ "$NABI_INSTALL_NO_MODIFY_PATH" != "1" ]; then
    case ":${PATH}:" in
      *":${NABI_INSTALL_BIN_LINK_DIR}:"*) ;;
      *)
        echo ""
        warn "${NABI_INSTALL_BIN_LINK_DIR} is not on your PATH"
        echo "  Add it, e.g.: export PATH=\"${NABI_INSTALL_BIN_LINK_DIR}:\$PATH\""
        ;;
    esac
  fi

  echo ""
  info "nabi $version installed."
  info "Next: run 'nabi ladder' to see the adoption path."
}

main "$@"
