#!/bin/sh
# botfile installer for macOS and Linux.
#
#   curl -fsSL https://botfile.org/install.sh | sh
#   curl -fsSL https://botfile.org/install.sh | sh -s -- v1.2.3   # pin a version
#
# Downloads the matching botfile binary from the Codeberg releases, verifies
# its sha256 against the release's checksums.txt, and drops it on your PATH.
# Override behaviour with environment variables:
#   BOTFILE_VERSION       version tag to install (default: the latest release)
#   BOTFILE_INSTALL_DIR   install directory (default: /usr/local/bin if writable,
#                         otherwise ~/.local/bin)
set -eu

owner=botfile
repo=botfile
api="https://codeberg.org/api/v1/repos/$owner/$repo"
dl_base="https://codeberg.org/$owner/$repo/releases/download"

die() { echo "install: $1" >&2; exit 1; }

# Download helper: prefer curl, fall back to wget.
if command -v curl >/dev/null 2>&1; then
	fetch() { curl -fsSL "$1"; }
	fetch_to() { curl -fsSL "$1" -o "$2"; }
elif command -v wget >/dev/null 2>&1; then
	fetch() { wget -qO- "$1"; }
	fetch_to() { wget -qO "$2" "$1"; }
else
	die "need curl or wget on PATH"
fi

# Detect OS.
os=$(uname -s)
case "$os" in
	Linux) os=linux ;;
	Darwin) os=darwin ;;
	*) die "unsupported OS '$os' (this installer covers Linux and macOS; on Windows use install.ps1)" ;;
esac

# Detect CPU architecture.
arch=$(uname -m)
case "$arch" in
	x86_64 | amd64) arch=amd64 ;;
	arm64 | aarch64) arch=arm64 ;;
	*) die "unsupported architecture '$arch'" ;;
esac

asset="botfile-$os-$arch"

# Resolve the version: positional arg, then $BOTFILE_VERSION, then latest release.
version=${1:-${BOTFILE_VERSION:-}}
if [ -z "$version" ]; then
	version=$(fetch "$api/releases/latest" 2>/dev/null |
		tr ',' '\n' |
		sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' |
		head -1) || true
	[ -n "$version" ] || die "could not determine the latest release (set BOTFILE_VERSION or pass a tag)"
fi

url="$dl_base/$version/$asset"

# Choose the install directory.
dir=${BOTFILE_INSTALL_DIR:-}
if [ -z "$dir" ]; then
	if [ -d /usr/local/bin ] && [ -w /usr/local/bin ]; then
		dir=/usr/local/bin
	else
		dir="$HOME/.local/bin"
	fi
fi
mkdir -p "$dir" || die "cannot create install directory $dir"

# Dry run (for testing): print the resolved plan and stop before downloading.
if [ -n "${BOTFILE_DRY_RUN:-}" ]; then
	echo "os=$os arch=$arch version=$version"
	echo "url=$url"
	echo "install_dir=$dir"
	exit 0
fi

# Download to a staging file in the install directory (so the final step is a
# same-filesystem rename), verify its sha256 against the release manifest, mark
# executable, then move into place. A failure leaves nothing half-installed.
echo "downloading botfile $version ($os/$arch)"
tmp=$(mktemp "$dir/.botfile-install.XXXXXX") || die "cannot stage in $dir"
trap 'rm -f "$tmp"' EXIT
fetch_to "$url" "$tmp" || die "download failed: $url"

sums=$(fetch "$dl_base/$version/checksums.txt") || die "download failed: $dl_base/$version/checksums.txt"
want=$(printf '%s\n' "$sums" | awk -v a="$asset" '$2 == a {print $1}')
[ -n "$want" ] || die "no checksum for $asset in the release's checksums.txt"
if command -v sha256sum >/dev/null 2>&1; then
	got=$(sha256sum "$tmp" | awk '{print $1}')
else
	got=$(shasum -a 256 "$tmp" | awk '{print $1}')
fi
[ "$got" = "$want" ] || die "checksum mismatch for $asset: the download does not match the release manifest"
echo "verified sha256 against checksums.txt"

chmod +x "$tmp"
mv "$tmp" "$dir/botfile"
trap - EXIT

echo "installed botfile to $dir/botfile"

# Verify if it is on PATH, otherwise tell the user how to add it.
case ":$PATH:" in
	*":$dir:"*) "$dir/botfile" version ;;
	*)
		echo "note: $dir is not on your PATH. Add it, for example:"
		echo "  export PATH=\"$dir:\$PATH\""
		;;
esac
