#!/bin/sh
# AIP binary installer. Override AIP_VERSION to pin a release, or
# AIP_INSTALL_DIR to choose an installation directory. No sudo is used.
set -eu

main() {
  fail() { printf 'aip install: %s\n' "$*" >&2; exit 1; }
  [ "$#" -eq 0 ] || fail 'Use AIP_VERSION and AIP_INSTALL_DIR environment variables; no positional arguments are accepted.'
  for tool in uname curl gzip mktemp mkdir chmod mv rm awk cat; do
    command -v "$tool" >/dev/null 2>&1 || fail "Required tool not found: $tool"
  done
  if command -v sha256sum >/dev/null 2>&1; then
    hash_tool=sha256sum
  elif command -v shasum >/dev/null 2>&1; then
    hash_tool=shasum
  else
    fail 'Install sha256sum or shasum before continuing.'
  fi
  case "$(uname -s)" in Darwin) os=darwin ;; Linux) os=linux ;; *) fail 'Supported systems: macOS and Linux.' ;; esac
  case "$(uname -m)" in arm64|aarch64) arch=arm64 ;; x86_64|amd64) arch=amd64 ;; *) fail 'Supported CPUs: ARM64 and x64.' ;; esac
  base=${AIP_DOWNLOAD_BASE:-https://aip-project.org}
  case "$base" in https://*) ;; *) fail 'AIP_DOWNLOAD_BASE must use HTTPS.' ;; esac
  base=${base%/}
  install_dir=${AIP_INSTALL_DIR:-${HOME:?HOME must be set}/.local/bin}
  case "$install_dir" in /*) ;; *) fail 'AIP_INSTALL_DIR must be an absolute path.' ;; esac
  temporary=$(mktemp -d "${TMPDIR:-/tmp}/aip-install.XXXXXX")
  staged=
  trap 'rm -rf "$temporary"; if [ -n "$staged" ]; then rm -f "$staged"; fi' EXIT
  trap 'exit 1' HUP INT TERM
  download() {
    curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' \
      --tlsv1.2 --connect-timeout 15 --max-time 180 --retry 2 "$1" -o "$2"
  }
  version=${AIP_VERSION:-}
  if [ -z "$version" ]; then
    download "$base/releases/latest" "$temporary/latest" || fail 'Could not resolve the latest release.'
    version=$(cat "$temporary/latest")
  fi
  case "$version" in v[0-9]*) ;; *) fail 'Invalid release version.' ;; esac
  case "$version" in *[!A-Za-z0-9._-]*) fail 'Invalid release version.' ;; esac
  artifact="aip-$version-$os-$arch.gz"
  release="$base/releases/$version"
  printf 'Downloading AIP %s for %s/%s...\n' "$version" "$os" "$arch"
  download "$release/SHA256SUMS" "$temporary/SHA256SUMS" || fail 'Could not download release checksums.'
  download "$release/$artifact" "$temporary/$artifact" || fail 'Could not download this platform build.'
  expected=$(awk -v name="$artifact" '$2 == name { print $1 }' "$temporary/SHA256SUMS")
  [ "${#expected}" -eq 64 ] || fail 'Missing or ambiguous checksum for this build.'
  case "$expected" in *[!0-9a-f]*) fail 'Invalid SHA-256 checksum.' ;; esac
  if [ "$hash_tool" = sha256sum ]; then
    actual=$(sha256sum "$temporary/$artifact")
  else
    actual=$(shasum -a 256 "$temporary/$artifact")
  fi
  actual=${actual%% *}
  [ "$actual" = "$expected" ] || fail 'Checksum mismatch. The existing installation was not changed.'
  mkdir -p "$install_dir"
  target="$install_dir/aip"
  [ ! -L "$target" ] || fail 'Refusing to replace an aip symlink.'
  if [ -e "$target" ] && [ ! -f "$target" ]; then fail 'The installation target is not a regular file.'; fi
  staged=$(mktemp "$install_dir/.aip-install.XXXXXX")
  gzip -dc "$temporary/$artifact" > "$staged" || fail 'Invalid compressed executable. The existing installation was not changed.'
  [ -s "$staged" ] || fail 'The executable is empty.'
  chmod 755 "$staged"
  mv -f "$staged" "$target"
  staged=
  printf 'Installed AIP %s to %s\n' "$version" "$target"
  case ":${PATH:-}:" in *":$install_dir:"*) ;; *) printf 'Add %s to your PATH to run aip from any directory.\n' "$install_dir" ;; esac
  printf 'Check the installation with: %s version\n' "$target"
}

main "$@"
