#!/bin/bash
# install.sh — 1-liner installer for orca
#
# Usage:
#   curl -fsSL https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh | bash
#   curl -fsSL https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh | bash -s -- --system
#   curl -fsSL https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh | bash -s -- --version v0.4.2
#
# Options:
#   --system         Install at system level (/usr/local/bin/orca, namespace /root/.orca). Requires root.
#   --version <tag>  Pin a specific version (e.g. v0.4.2). Default: latest release.
#   --check           Dry-run: print the version + asset URL + install path without writing.
#   --help, -h       Show this help.
#
# Behavior:
#   - Downloads the release tarball from the public Gitea release URL.
#   - Extracts the orca binary to the install path.
#   - If the resolved release (latest or pinned) has no matching binary
#     asset, walks backward through recent releases to find one that does,
#     and prints a warning. (REQ-098 — the v0.8.x releases shipped with
#     zero binary assets, causing install to resolve to v0.4.5.)
#   - If an existing orca binary is found, reads its version and prints
#     "updated from X to Y" (in-place update; preserves config/db/certs).
#   - Idempotent: re-running with the same version reinstalls the binary.
#   - Never touches the namespace dir (~/.orca or /root/.orca) — that's user state.

set -euo pipefail

GITEA_URL="${GITEA_URL:-https://git.cloudinit.dev}"
GITEA_OWNER="${GITEA_OWNER:-coreci}"
GITEA_REPO="${GITEA_REPO:-orca}"

SYSTEM=false
VERSION=""
CHECK=false
INSTALL_BIN=""
NAMESPACE_DIR=""

warn() {
  printf "  \033[1;33m!\033[0m %s\n" "$*" >&2
}

err()  { echo "install: error: $*" >&2; exit 1; }
info() { echo "install: $*"; }

usage() {
  sed -n '2,/^$/p' "$0" | sed 's/^# \?//' >&2
  exit 0
}

# --- parse args ------------------------------------------------------------

while [ $# -gt 0 ]; do
  case "$1" in
    --system)  SYSTEM=true; shift ;;
    --version) VERSION="${2:-}"; shift 2 ;;
    --version=*) VERSION="${1#*=}"; shift ;;
    --check)   CHECK=true; shift ;;
    --help|-h) usage ;;
    *) err "unknown argument: $1 (try --help)" ;;
  esac
done

# --- determine install paths ----------------------------------------------

if [ "$SYSTEM" = "true" ]; then
  if [ "$(id -u)" -ne 0 ]; then
    err "--system requires root (uid 0). Re-run with sudo or drop --system for user-level install."
  fi
  INSTALL_BIN="/usr/local/bin/orca"
  NAMESPACE_DIR="/root/.orca"
else
  INSTALL_BIN="${HOME}/.local/bin/orca"
  NAMESPACE_DIR="${HOME}/.orca"
fi

INSTALL_DIR="$(dirname "$INSTALL_BIN")"

# --- determine version ----------------------------------------------------

if [ -z "$VERSION" ]; then
  info "querying latest release from ${GITEA_URL}..."
  VERSION="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/latest" \
    | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
    | head -1)"
  if [ -z "$VERSION" ]; then
    err "could not determine latest release version from Gitea API"
  fi
fi
info "version: ${VERSION}"

# --- detect arch ----------------------------------------------------------

ARCH="$(uname -m)"
case "$ARCH" in
  x86_64)    ARCH=amd64 ;;
  aarch64|arm64) ARCH=arm64 ;;
  armv7l)    ARCH=armv7 ;;
  *) err "unsupported architecture: ${ARCH} (supported: amd64, arm64, armv7)" ;;
esac

OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
TARBALL="orca-${VERSION}-${OS}-${ARCH}.tar.gz"

# --- find asset download URL (with fallback walk — REQ-098) --------------
#
# The v0.8.x releases shipped with zero binary assets attached, causing
# install to error out on the latest release. If the resolved release
# (latest or --version) lacks the matching tarball, walk backward through
# recent releases to find one that carries it, and print a warning.

find_asset_url() {
  # $1 = tag. Prints the browser_download_url for the matching tarball, or empty.
  # The `|| true` prevents set -e + pipefail from exiting the script when
  # grep finds no match (exit 1) — an empty result is a valid outcome.
  local tag="$1"
  curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/tags/${tag}" \
    | sed -n 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
    | grep "/${TARBALL}\$" \
    | head -1 || true
}

info "locating asset ${TARBALL} in release ${VERSION}..."
ASSET_URL="$(find_asset_url "$VERSION")"

if [ -z "$ASSET_URL" ]; then
  info "WARNING: release ${VERSION} has no ${TARBALL} asset. Walking back through recent releases..."
  # The /releases list endpoint returns assets inline (browser_download_url
  # appears within each release's assets array). Extract all download URLs
  # from the list response and find the first (newest) one matching our
  # OS+arch tarball pattern (any version). This avoids per-release API calls.
  ASSET_URL="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases?limit=50" \
    | grep -oE '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*"' \
    | sed -n 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
    | grep -E "/orca-[^/]*-${OS}-${ARCH}\.tar\.gz$" \
    | head -1 || true)"
  if [ -n "$ASSET_URL" ]; then
    # Extract the version from the URL (e.g. .../download/v0.4.5/orca-...)
    FALLBACK_VERSION="$(echo "$ASSET_URL" | sed -n 's|.*/download/\([^/]*\)/.*|\1|p')"
    info "WARNING: latest release ${VERSION} has no binary asset; falling back to ${FALLBACK_VERSION} which has orca-${FALLBACK_VERSION}-${OS}-${ARCH}.tar.gz."
    VERSION="$FALLBACK_VERSION"
  else
    err "could not find any release with a ${OS}-${ARCH} tarball in the last 50 releases. Check that a release exists with a linux-${ARCH} binary."
  fi
fi
info "asset: ${ASSET_URL}"

# --- in-place update detection -------------------------------------------

OLD_VERSION=""
if [ -x "$INSTALL_BIN" ]; then
  OLD_VERSION="$("$INSTALL_BIN" version --json 2>/dev/null | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1 || echo "")"
fi

# --- --check dry-run (D-194) ---------------------------------------------
# Print what would be installed without writing anything.

if [ "$CHECK" = "true" ]; then
  info "dry-run (--check): no files will be written"
  info "  would install:  orca ${VERSION}"
  info "  asset:          ${ASSET_URL}"
  info "  binary path:     ${INSTALL_BIN}"
  info "  namespace root:  ${NAMESPACE_DIR}"
  if [ -n "$OLD_VERSION" ]; then
    info "  current:        ${OLD_VERSION} (would update to ${VERSION})"
  else
    info "  current:        (not installed)"
  fi
  exit 0
fi

# --- download + extract ---------------------------------------------------

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

info "downloading..."
curl -fsSL -o "${TMPDIR}/${TARBALL}" "$ASSET_URL"

# REQ-132 / F14: verify tarball checksum before extraction.
# Fetch SHA256SUMS from the same release; fail closed on mismatch.
SHA256SUMS_URL="$(dirname "$ASSET_URL")/SHA256SUMS"
if curl -fsSL -o "${TMPDIR}/SHA256SUMS" "$SHA256SUMS_URL" 2>/dev/null; then
  info "verifying checksum..."
  (cd "$TMPDIR" && grep -F "$TARBALL" SHA256SUMS | sha256sum -c -) || {
    err "checksum verification failed (REQ-132); refusing to install"
    exit 1
  }
else
  warn "no SHA256SUMS found at $SHA256SUMS_URL; skipping checksum (insecure)"
fi

info "extracting..."
tar -xzf "${TMPDIR}/${TARBALL}" -C "$TMPDIR"

if [ ! -f "${TMPDIR}/orca" ]; then
  err "tarball did not contain an 'orca' binary"
fi

# --- install --------------------------------------------------------------

mkdir -p "$INSTALL_DIR"
install -m 0755 "${TMPDIR}/orca" "$INSTALL_BIN"

# --- report ---------------------------------------------------------------

if [ -n "$OLD_VERSION" ]; then
  if [ "$OLD_VERSION" = "$VERSION" ]; then
    info "✓ reinstalled orca ${VERSION} at ${INSTALL_BIN}"
  else
    info "✓ updated orca from ${OLD_VERSION} to ${VERSION} at ${INSTALL_BIN}"
  fi
else
  info "✓ installed orca ${VERSION} to ${INSTALL_BIN}"
fi

if [ "$SYSTEM" = "true" ]; then
  info "  namespace root: ${NAMESPACE_DIR} (use 'orca --system init' to initialize)"
else
  info "  namespace root: ${NAMESPACE_DIR} (use 'orca init' to initialize)"
  if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
    info "  NOTE: $INSTALL_DIR is not on your PATH. Add it:"
    info "    export PATH=\"\$PATH:$INSTALL_DIR\""
  fi
fi

info "  verify: ${INSTALL_BIN} version"