#!/bin/sh
# rickub CLI installer — "the git that's never gonna let you down."
#
# Installs the `rickub` command-line client (https://rickub.com/rickub/cli).
# Safe to pipe into a shell:
#
#     curl -sSL https://rickub.com/install.sh | sh
#
# What it does: detect your OS/arch, resolve the latest published release,
# download the matching binary over HTTPS, verify its SHA-256 against the
# release's SHA256SUMS, and install `rickub` onto your PATH. Re-running it
# upgrades in place.
#
# Environment overrides (all optional):
#   RICKUB_CLI_VERSION   Pin a release tag (e.g. v0.1.0-rc.11). Default: latest.
#   RICKUB_INSTALL_DIR   Where to install. Default: /usr/local/bin, falling back
#                        to ~/.local/bin when that is not writable.
#   RICKUB_SITE          Base site URL. Default: https://rickub.com.
#   RICKUB_CLI_REPO      Repo hosting the releases. Default: rickub/cli.
#
# POSIX sh only — no bashisms. Exit non-zero on any failure (fails closed on a
# checksum mismatch), and never touches files outside the install dir + a temp
# scratch dir it cleans up.

set -eu

# ---------------------------------------------------------------- configuration
SITE="${RICKUB_SITE:-https://rickub.com}"
REPO="${RICKUB_CLI_REPO:-rickub/cli}"
BIN="rickub"

usage() {
	cat <<EOF
rickub CLI installer

Usage:
  curl -sSL ${SITE}/install.sh | sh
  RICKUB_CLI_VERSION=v0.1.0-rc.11 curl -sSL ${SITE}/install.sh | sh
  sh install.sh [--help]

Environment overrides:
  RICKUB_CLI_VERSION   pin a release tag (default: latest)
  RICKUB_INSTALL_DIR   install dir (default: /usr/local/bin, else ~/.local/bin)
  RICKUB_SITE          base site URL (default: https://rickub.com)
  RICKUB_CLI_REPO      releases repo (default: rickub/cli)
EOF
}

case "${1:-}" in
	-h | --help)
		usage
		exit 0
		;;
esac

# ---------------------------------------------------------------- helpers
err() {
	echo "install: $*" >&2
	exit 1
}

info() { echo "==> $*"; }

have() { command -v "$1" >/dev/null 2>&1; }

# download URL -> FILE, following redirects, failing on any HTTP error.
download() {
	_url="$1"
	_out="$2"
	if have curl; then
		curl -fsSL "$_url" -o "$_out"
	elif have wget; then
		wget -q -O "$_out" "$_url"
	else
		err "need either curl or wget installed"
	fi
}

# print the Location header target of URL without following it. Used to resolve
# the latest release: /$REPO/releases/latest 302-redirects to the tag page.
redirect_target() {
	_url="$1"
	if have curl; then
		curl -fsSI "$_url" | awk 'tolower($1) == "location:" { print $2 }' | tr -d '\r' | tail -n1
	elif have wget; then
		wget -S --spider --max-redirect=0 "$_url" 2>&1 |
			awk 'tolower($1) == "location:" { print $2 }' | tr -d '\r' | tail -n1
	else
		err "need either curl or wget installed"
	fi
}

# print the sha256 hex digest of FILE, or empty if no tool is available.
sha256_of() {
	_f="$1"
	if have sha256sum; then
		sha256sum "$_f" | awk '{ print $1 }'
	elif have shasum; then
		shasum -a 256 "$_f" | awk '{ print $1 }'
	elif have openssl; then
		openssl dgst -sha256 "$_f" | awk '{ print $NF }'
	else
		echo ""
	fi
}

# ---------------------------------------------------------------- platform
os_raw="$(uname -s)"
arch_raw="$(uname -m)"

case "$os_raw" in
	Linux) OS="linux" ;;
	Darwin) OS="darwin" ;;
	*) err "unsupported OS '$os_raw' (rickub ships linux and darwin builds)" ;;
esac

case "$arch_raw" in
	x86_64 | amd64) ARCH="amd64" ;;
	aarch64 | arm64) ARCH="arm64" ;;
	*) err "unsupported architecture '$arch_raw' (rickub ships amd64 and arm64 builds)" ;;
esac

# ---------------------------------------------------------------- resolve version
if [ -n "${RICKUB_CLI_VERSION:-}" ]; then
	TAG="$RICKUB_CLI_VERSION"
	info "using pinned version $TAG"
else
	info "resolving the latest release..."
	loc="$(redirect_target "$SITE/$REPO/releases/latest")"
	[ -n "$loc" ] || err "could not resolve the latest release from $SITE/$REPO/releases/latest"
	# loc is like /rickub/cli/releases/v0.1.0-rc.11 — the tag is its last segment.
	TAG="${loc##*/}"
	[ -n "$TAG" ] || err "could not parse a release tag from '$loc'"
	info "latest release is $TAG"
fi

# Asset filenames carry the version WITHOUT the leading v (rickub_0.1.0-rc.11_...),
# while the download path uses the tag AS-IS (v0.1.0-rc.11). Strip one leading v.
VERSION="${TAG#v}"
ASSET="${BIN}_${VERSION}_${OS}_${ARCH}.tar.gz"
BASE_URL="$SITE/$REPO/releases/download/$TAG"

# ---------------------------------------------------------------- download
TMP="$(mktemp -d 2>/dev/null || mktemp -d -t rickub)"
cleanup() { rm -rf "$TMP"; }
trap cleanup EXIT INT TERM

info "downloading $ASSET"
download "$BASE_URL/$ASSET" "$TMP/$ASSET"

# ---------------------------------------------------------------- verify
info "verifying checksum"
if download "$BASE_URL/SHA256SUMS" "$TMP/SHA256SUMS" 2>/dev/null; then
	expected="$(awk -v f="$ASSET" '$2 == f { print $1 }' "$TMP/SHA256SUMS")"
	if [ -z "$expected" ]; then
		err "no checksum for $ASSET in SHA256SUMS"
	fi
	actual="$(sha256_of "$TMP/$ASSET")"
	if [ -z "$actual" ]; then
		echo "install: no sha256 tool (sha256sum/shasum/openssl) found — skipping verification" >&2
	elif [ "$expected" != "$actual" ]; then
		err "checksum mismatch for $ASSET: expected $expected, got $actual"
	else
		info "checksum OK"
	fi
else
	echo "install: SHA256SUMS not published for $TAG — skipping verification" >&2
fi

# ---------------------------------------------------------------- extract
info "extracting"
case "$ASSET" in
	*.tar.gz | *.tgz)
		tar -xzf "$TMP/$ASSET" -C "$TMP"
		;;
	*)
		# A bare binary (no archive): the download IS the binary.
		cp "$TMP/$ASSET" "$TMP/$BIN"
		;;
esac
[ -f "$TMP/$BIN" ] || err "extracted archive did not contain a '$BIN' binary"
chmod +x "$TMP/$BIN"

# ---------------------------------------------------------------- install
if [ -n "${RICKUB_INSTALL_DIR:-}" ]; then
	DEST="$RICKUB_INSTALL_DIR"
else
	DEST="/usr/local/bin"
fi

install_into() {
	# install_into DIR [sudo] — returns non-zero if it could not place the binary.
	_dir="$1"
	_sudo="${2:-}"
	$_sudo mkdir -p "$_dir" 2>/dev/null || return 1
	$_sudo cp "$TMP/$BIN" "$_dir/$BIN" 2>/dev/null || return 1
	$_sudo chmod +x "$_dir/$BIN" 2>/dev/null || return 1
	return 0
}

PATH_HINT=""
if install_into "$DEST"; then
	:
elif [ "$DEST" = "/usr/local/bin" ] && have sudo && install_into "$DEST" sudo; then
	info "installed with sudo"
elif [ -z "${RICKUB_INSTALL_DIR:-}" ] && install_into "$HOME/.local/bin"; then
	DEST="$HOME/.local/bin"
	case ":$PATH:" in
		*":$DEST:"*) ;;
		*) PATH_HINT="$DEST is not on your PATH — add it: export PATH=\"$DEST:\$PATH\"" ;;
	esac
else
	err "could not install to $DEST (set RICKUB_INSTALL_DIR to a writable directory)"
fi

# ---------------------------------------------------------------- done
info "installed $BIN to $DEST/$BIN"
if "$DEST/$BIN" version >/dev/null 2>&1; then
	"$DEST/$BIN" version || true
fi
echo ""
echo "You're set — the smartest git in the universe is on your machine."
echo "Next: $BIN auth login --host $SITE"
if [ -n "$PATH_HINT" ]; then
	echo ""
	echo "Note: $PATH_HINT"
fi
