#!/bin/sh
# Avocado CLI installer
# Usage: curl -fsSL <#TODO: replace-this-with-the-actual-url> | sh
#
# Environment variables:
#   AVOCADO_VERSION   Pin a specific version (default: latest)
#   AVOCADO_INSTALL   Custom install directory (default: ~/.local/bin)

set -eu

REPO="avocado-linux/avocado-cli"
GITHUB_API="https://api.github.com"
GITHUB_DOWNLOAD="https://github.com"
BINARY_NAME="avocado"
DEFAULT_INSTALL_DIR="$HOME/.local/bin"

# --- Colors ---

setup_colors() {
	if [ -t 1 ] && [ -t 2 ]; then
		RED='\033[0;31m'
		GREEN='\033[0;32m'
		BLUE='\033[0;34m'
		YELLOW='\033[0;33m'
		BOLD='\033[1m'
		RESET='\033[0m'
	else
		RED=''
		GREEN=''
		BLUE=''
		YELLOW=''
		BOLD=''
		RESET=''
	fi
}

info() { printf "${BLUE}info${RESET}: %s\n" "$@"; }
warn() { printf "${YELLOW}warn${RESET}: %s\n" "$@" >&2; }
err() { printf "${RED}error${RESET}: %s\n" "$@" >&2; }

# --- Utilities ---

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

need_cmd() {
	if ! check_cmd "$1"; then
		err "Required command not found: $1"
		exit 1
	fi
}

# --- Download abstraction (curl or wget) ---

download_to_stdout() {
	if check_cmd curl; then
		curl -fsSL "$1"
	elif check_cmd wget; then
		wget -qO- "$1"
	else
		err "Neither curl nor wget found. Install one and try again."
		exit 1
	fi
}

download_to_file() {
	if check_cmd curl; then
		curl -fsSL -o "$2" "$1"
	elif check_cmd wget; then
		wget -qO "$2" "$1"
	else
		err "Neither curl nor wget found. Install one and try again."
		exit 1
	fi
}

# --- Platform detection ---

detect_os() {
	_os="$(uname -s)"
	case "$_os" in
	Darwin) OS="darwin" ;;
	Linux) OS="linux" ;;
	MINGW* | MSYS* | CYGWIN*) OS="windows" ;;
	*)
		err "Unsupported operating system: $_os"
		err "Supported: macOS, Linux, Windows (MSYS/Cygwin)"
		exit 1
		;;
	esac
}

detect_arch() {
	_arch="$(uname -m)"
	case "$_arch" in
	x86_64 | amd64) ARCH="x86_64" ;;
	aarch64 | arm64) ARCH="aarch64" ;;
	*)
		err "Unsupported architecture: $_arch"
		err "Supported: x86_64, aarch64 (arm64)"
		exit 1
		;;
	esac
}

resolve_target_triple() {
	case "${OS}_${ARCH}" in
	darwin_aarch64) TARGET="aarch64-apple-darwin" ;;
	darwin_x86_64) TARGET="x86_64-apple-darwin" ;;
	linux_aarch64) TARGET="aarch64-unknown-linux-musl" ;;
	linux_x86_64) TARGET="x86_64-unknown-linux-musl" ;;
	windows_x86_64) TARGET="x86_64-pc-windows-msvc" ;;
	*)
		err "No prebuilt binary for ${OS}/${ARCH}"
		exit 1
		;;
	esac
}

# --- Version resolution ---

resolve_version() {
	if [ -n "${AVOCADO_VERSION:-}" ]; then
		VERSION="$AVOCADO_VERSION"
		info "Using pinned version: $VERSION"
		return
	fi

	info "Fetching latest release version..."
	_response="$(download_to_stdout "$GITHUB_API/repos/$REPO/releases/latest")"

	# Extract tag_name from JSON without jq
	VERSION="$(printf '%s' "$_response" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | grep -o '"[^"]*"$' | tr -d '"')"

	if [ -z "$VERSION" ]; then
		err "Could not determine latest version from GitHub API"
		err "You may be rate-limited. Set AVOCADO_VERSION to install a specific version."
		exit 1
	fi

	info "Latest version: $VERSION"
}

# --- Cleanup ---

cleanup() {
	if [ -n "${TMPDIR_INSTALL:-}" ] && [ -d "$TMPDIR_INSTALL" ]; then
		rm -rf "$TMPDIR_INSTALL"
	fi
}

# --- Install ---

check_existing_install() {
	# If the user explicitly requested a specific version or a custom install
	# directory, do not exit early just because a binary is found on PATH.
	# This allows reinstalling a pinned version or installing alongside an
	# existing installation.
	if [ -n "${AVOCADO_VERSION:-}" ] || [ -n "${AVOCADO_INSTALL:-}" ]; then
		return 0
	fi

	if check_cmd "$BINARY_NAME"; then
		_existing_path="$(command -v "$BINARY_NAME" || true)"
		_existing_version="$("$BINARY_NAME" --version 2>/dev/null || true)"

		printf "\n"
		printf "${GREEN}${BOLD}%s is already installed.${RESET}\n" "$BINARY_NAME"
		if [ -n "$_existing_version" ]; then
			printf "  Version: %s\n" "$_existing_version"
		fi
		if [ -n "$_existing_path" ]; then
			printf "  Location: %s\n" "$_existing_path"
		fi
		printf "\n"
		printf "To upgrade to the latest version, run:\n"
		printf "  %s upgrade\n" "$BINARY_NAME"
		printf "\n"
		exit 0
	fi
}

install_binary() {
	INSTALL_DIR="${AVOCADO_INSTALL:-$DEFAULT_INSTALL_DIR}"

	# Create temp directory
	TMPDIR_INSTALL="$(mktemp -d)" || {
		err "Failed to create temp directory"
		exit 1
	}
	trap cleanup EXIT INT TERM

	# Construct download URL
	_archive="avocado-${VERSION}_${TARGET}.tar.gz"
	_url="${GITHUB_DOWNLOAD}/${REPO}/releases/download/${VERSION}/${_archive}"

	# Download
	info "Downloading avocado ${VERSION} for ${TARGET}..."
	if ! download_to_file "$_url" "${TMPDIR_INSTALL}/${_archive}"; then
		err "Failed to download avocado ${VERSION}."
		err "Version '${VERSION}' may not exist. Check available releases at:"
		err "  https://github.com/${REPO}/releases"
		exit 1
	fi

	# Extract
	info "Extracting..."
	tar -xzf "${TMPDIR_INSTALL}/${_archive}" -C "${TMPDIR_INSTALL}"

	# Determine binary name
	if [ "$OS" = "windows" ]; then
		_binary="avocado.exe"
	else
		_binary="avocado"
	fi

	# Verify extracted binary exists
	if [ ! -f "${TMPDIR_INSTALL}/${_binary}" ]; then
		err "Expected binary '${_binary}' not found in archive"
		exit 1
	fi

	# Create install directory
	mkdir -p "$INSTALL_DIR" || {
		err "Failed to create install directory: $INSTALL_DIR"
		err "Set AVOCADO_INSTALL to a writable path, or create it manually."
		exit 1
	}

	# Install binary
	mv "${TMPDIR_INSTALL}/${_binary}" "${INSTALL_DIR}/${_binary}"
	chmod +x "${INSTALL_DIR}/${_binary}"

	# Verify
	if "${INSTALL_DIR}/${_binary}" --version >/dev/null 2>&1; then
		_installed_version="$("${INSTALL_DIR}/${_binary}" --version 2>&1)"
		printf "\n"
		printf "${GREEN}${BOLD}%s installed successfully!${RESET}\n" "$_installed_version"
	else
		printf "\n"
		printf "${GREEN}${BOLD}avocado ${VERSION} installed successfully!${RESET}\n"
	fi
	printf "  Location: %s/%s\n" "$INSTALL_DIR" "$_binary"
	printf "\n"
}

# --- PATH check ---

check_path() {
	INSTALL_DIR="${AVOCADO_INSTALL:-$DEFAULT_INSTALL_DIR}"

	case ":${PATH}:" in
	*":${INSTALL_DIR}:"*)
		return
		;;
	esac

	warn "${INSTALL_DIR} is not in your PATH"
	printf "\n"
	printf "Add it to your shell profile:\n"
	printf "\n"

	_shell="$(basename "${SHELL:-sh}")"
	case "$_shell" in
	zsh)
		printf "  echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.zshrc\n"
		printf "  source ~/.zshrc\n"
		;;
	bash)
		printf "  echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc\n"
		printf "  source ~/.bashrc\n"
		;;
	fish)
		printf "  fish_add_path %s\n" "$INSTALL_DIR"
		;;
	*)
		printf "  export PATH=\"%s:\$PATH\"\n" "$INSTALL_DIR"
		;;
	esac
	printf "\n"
}

# --- Main ---

main() {
	setup_colors

	printf "\n"
	printf "${BOLD}Avocado CLI Installer${RESET}\n"
	printf "\n"

	need_cmd uname
	need_cmd mktemp
	need_cmd tar
	need_cmd grep
	need_cmd chmod

	check_existing_install
	detect_os
	detect_arch
	resolve_target_triple
	resolve_version
	install_binary
	check_path
}

main "$@"
