#!/bin/sh
# HTTPS and same-host SHA-256 checksums detect corruption, not publisher compromise.
set -eu

REPO="${COBI_DIST_REPO:-jacobiajohnson/cobi-cli-dist}"
PREFIX="${PREFIX:-$HOME/.local/bin}"
VERSION="${VERSION:-}"

fail() { printf '%s\n' "$1" >&2; exit "${2:-1}"; }
usage() { printf '%s\n' 'Usage: install.sh [--version <version>] [--prefix <directory>]'; }
valid_version() {
  case "$1" in ''|[!A-Za-z0-9]*|*[!A-Za-z0-9._-]*) return 1;; esac
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --version)
      [ "$#" -ge 2 ] && [ -n "$2" ] || fail 'Missing --version value' 2
      VERSION="$2"
      valid_version "$VERSION" || fail 'Invalid version token' 2
      shift 2;;
    --prefix)
      [ "$#" -ge 2 ] && [ -n "$2" ] || fail 'Missing --prefix value' 2
      PREFIX="$2"
      shift 2;;
    -h|--help) usage; exit 0;;
    *) usage >&2; fail 'Unknown argument' 2;;
  esac
done

[ -z "$VERSION" ] || valid_version "$VERSION" || fail 'Invalid version token' 2
case "$REPO" in *[!A-Za-z0-9._/-]*|/*|*/|*/*/*|*..*) fail 'Invalid distribution repository' 2;; esac
case "$REPO" in */*) ;; *) fail 'Expected owner/repository' 2;; esac
[ -n "$PREFIX" ] || fail 'Empty installation prefix' 2

for command in curl uname tr awk mktemp mkdir chmod mv rm; do
  command -v "$command" >/dev/null 2>&1 || fail "Required utility missing: $command"
done
if command -v sha256sum >/dev/null 2>&1; then
  checksum() { sha256sum "$1"; }
elif command -v shasum >/dev/null 2>&1; then
  checksum() { shasum -a 256 "$1"; }
else
  fail 'Install sha256sum or shasum before running this installer'
fi

os=$(uname -s)
arch=$(uname -m)
case "$os" in Darwin) platform=darwin;; *) fail "Unsupported platform: $os (macOS required)" 2;; esac
case "$arch" in arm64|aarch64) cpu=arm64;; x86_64|amd64) cpu=x64;; *) fail "Unsupported architecture: $arch" 2;; esac
artifact="cobi-${platform}-${cpu}"
BASE_URL="https://github.com/${REPO}/releases"

# Restrict both the initial request and every redirect to HTTPS.
download() { curl --proto '=https' --proto-redir '=https' --connect-timeout 10 --max-time 120 -fsSL "$@"; }
if [ -z "$VERSION" ]; then
  latest=$(download -I -o /dev/null -w '%{url_effective}' "${BASE_URL}/latest")
  case "$latest" in "${BASE_URL}/tag/"*) VERSION=${latest#"${BASE_URL}/tag/"};; *) fail 'Unexpected latest-release redirect';; esac
  valid_version "$VERSION" || fail 'Could not resolve a valid release version'
fi

case "$PREFIX" in /*) ;; *) PREFIX="$PWD/$PREFIX";; esac
mkdir -p "$PREFIX"
PREFIX=$(cd "$PREFIX" && pwd -P)
target="$PREFIX/cobi"
[ ! -L "$target" ] || fail 'Refusing to replace a symlink destination'
[ ! -e "$target" ] || [ -f "$target" ] || fail 'Destination is not a regular file'

# A private directory on the destination filesystem makes the final rename atomic.
umask 077
tmpdir=$(mktemp -d "$PREFIX/.cobi-install.XXXXXX")
cleanup() { rm -rf "$tmpdir"; }
trap cleanup 0
trap 'exit 130' INT
trap 'exit 143' TERM

download "${BASE_URL}/download/${VERSION}/SHA256SUMS" -o "$tmpdir/SHA256SUMS"
expected=$(awk -v artifact="$artifact" '
  NF == 0 { next }
  NF != 2 || length($1) != 64 || $1 ~ /[^[:xdigit:]]/ || $2 ~ /[^A-Za-z0-9._-]/ { bad=1; next }
  seen[$2]++ { bad=1 }
  $2 == artifact { found++; checksum=tolower($1) }
  END { if (bad || found != 1) exit 1; print checksum }
' "$tmpdir/SHA256SUMS") || fail 'Missing, duplicate, or malformed checksum entry'
download "${BASE_URL}/download/${VERSION}/${artifact}" -o "$tmpdir/$artifact"
actual=$(checksum "$tmpdir/$artifact")
actual=${actual%% *}
[ "$expected" = "$actual" ] || fail "Checksum mismatch for $artifact"

chmod 755 "$tmpdir/$artifact"
[ ! -L "$target" ] || fail 'Destination became a symlink'
[ ! -e "$target" ] || [ -f "$target" ] || fail 'Destination is not a regular file'
mv -f "$tmpdir/$artifact" "$target"
printf 'Installed cobi %s -> %s\n' "$VERSION" "$target"
case ":$PATH:" in *":$PREFIX:"*) ;; *) printf 'Add this directory to your PATH: %s\n' "$PREFIX";; esac
