#!/usr/bin/env bash
#
# Checks the CLI installer served at https://warmbly.com/cli.sh, and its
# Windows counterpart at /cli.ps1.
#
# Both are served verbatim out of site/public, so this runs against the exact
# bytes a `curl -fsSL https://warmbly.com/cli.sh | sh` executes:
#
#   * it parses as POSIX sh, in dash and not only in bash
#   * shellcheck has nothing to say about it
#   * --help and --dry-run work with no network and no terminal, because that
#     is how someone reads it before trusting it, and --dry-run writes nothing
#   * a real install against a local mirror produces a working binary, puts it
#     on PATH and writes completions
#   * a tampered checksum stops the install rather than warning about it
#   * --uninstall removes exactly what it wrote and nothing else
#   * the platforms it will download match the ones we actually build
#   * the published checksum matches, so "download, verify, read, run" verifies
set -euo pipefail

cd "$(dirname "$0")/.."
SCRIPT=site/public/cli.sh
PS_SCRIPT=site/public/cli.ps1
SUMFILE=site/public/cli.sh.sha256

fail() { printf '\n\033[31m✗\033[0m %s\n' "$*" >&2; exit 1; }
pass() { printf '\033[32m✓\033[0m %s\n' "$*"; }

# macOS ships shasum and not GNU sha256sum; this check has to run there too.
sha256_all() {
  if command -v sha256sum >/dev/null 2>&1; then sha256sum "$@"; else shasum -a 256 "$@"; fi
}
sha256_verify() {
  if command -v sha256sum >/dev/null 2>&1; then sha256sum -c "$@"; else shasum -a 256 -c "$@"; fi
}

[[ -f $SCRIPT ]] || fail "$SCRIPT is missing"
[[ -f $PS_SCRIPT ]] || fail "$PS_SCRIPT is missing"

# The script is executed by whatever /bin/sh is on the machine, which on Debian
# and Ubuntu is dash. Checking with bash alone would let a bashism through to
# exactly the hosts this is aimed at.
if command -v dash >/dev/null 2>&1; then
  dash -n "$SCRIPT" || fail "the installer is not valid POSIX sh (dash -n)"
  pass "parses as POSIX sh"
else
  sh -n "$SCRIPT" || fail "the installer does not parse"
  pass "parses (dash not installed; POSIX check was approximate)"
fi

if command -v shellcheck >/dev/null 2>&1; then
  shellcheck -s sh "$SCRIPT" || fail "shellcheck found problems in the installer"
  pass "shellcheck clean ($(shellcheck --version | awk '/^version:/ {print $2}'))"
else
  echo "· shellcheck not installed; skipped"
fi

# --help must work before anything is set up, which is where an unbound
# variable under set -u would otherwise hide.
sh "$SCRIPT" --help >/dev/null || fail "--help failed"
pass "--help works"

# A rejected flag has to print its message. This used to abort with
# "C_RED: unbound variable" instead, because parse_args runs before the colours
# are set and `set -u` turns an unset variable into a fatal error. Only --help
# and --dry-run were exercised, so nothing caught it.
for bad in --nonsense --dir; do
  # The exit status matters as much as the message: a script that explains the
  # problem and then exits 0 tells every caller the install succeeded.
  if out=$(sh "$SCRIPT" "$bad" 2>&1); then
    fail "$bad exited 0; a rejected flag has to fail"
  fi
  case "$out" in
    *"unbound variable"*) fail "$bad aborted with an unbound variable instead of an error message" ;;
  esac
  case "$out" in
    *"unknown option"*|*"needs a path"*) ;;
    *) fail "$bad did not explain itself:
$out" ;;
  esac
done
pass "a rejected flag explains itself"

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

# --dry-run reaches its end with no network and, above all, writes nothing.
HOME="$work/dryhome" SHELL=/bin/bash sh "$SCRIPT" --dry-run --no-color --dir "$work/dryhome/bin" >/dev/null 2>&1 \
  || fail "--dry-run failed"
[[ ! -e "$work/dryhome" ]] || fail "--dry-run created $work/dryhome; it must write nothing"
pass "--dry-run runs and writes nothing"

# Every platform the installer will ask for has to be one we build, and the
# other way round. A mismatch is a 404 for whoever runs it on that machine.
script_platforms=$(sed -n 's/^PLATFORMS="\(.*\)"$/\1/p' "$SCRIPT" | tr ' ' '\n' | sort)
build_platforms=$(sed -n 's/^PLATFORMS="\(.*\)"$/\1/p' scripts/build-cli.sh | tr ' ' '\n' | sed 's|/|_|' | grep -v '^windows' | sort)
if [[ "$script_platforms" != "$build_platforms" ]]; then
  fail "cli.sh and scripts/build-cli.sh disagree about platforms:
installer builds for:
$script_platforms
release builds:
$build_platforms"
fi
pass "installer and release agree on platforms"

# ─────────────────────────────────────────────────────────────────────────
# A real install, against a mirror on disk. file:// keeps this offline, which
# is what lets it run in CI without reaching GitHub.
# ─────────────────────────────────────────────────────────────────────────

mirror="$work/mirror"
mkdir -p "$mirror" "$work/stage/completions"

# A stand-in for the real binary: the installer only needs something that runs
# and answers `version`, and building the real CLI here would make this check
# a minute slower for nothing.
cat > "$work/stage/warmbly" <<'STUB'
#!/bin/sh
[ "${1:-}" = version ] && echo "warmbly v0.0.0-test (test)" && exit 0
exit 0
STUB
chmod +x "$work/stage/warmbly"
echo "# completions" > "$work/stage/completions/warmbly.bash"
echo "# completions" > "$work/stage/completions/warmbly.zsh"
echo "# completions" > "$work/stage/completions/warmbly.fish"
cp LICENSE "$work/stage/" 2>/dev/null || echo license > "$work/stage/LICENSE"

host_os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$(uname -m)" in
  x86_64|amd64) host_arch=amd64 ;;
  arm64|aarch64) host_arch=arm64 ;;
  *) host_arch=amd64 ;;
esac
asset="warmbly_${host_os}_${host_arch}.tar.gz"
tar -czf "$mirror/$asset" -C "$work/stage" .
( cd "$mirror" && sha256_all "$asset" > checksums.txt )

home="$work/home"
mkdir -p "$home"
HOME="$home" SHELL=/bin/bash sh "$SCRIPT" \
  --base-url "file://$mirror" --dir "$home/bin" --no-color >/dev/null 2>&1 \
  || fail "installing from a local mirror failed"

[[ -x "$home/bin/warmbly" ]] || fail "the installer did not produce $home/bin/warmbly"
[[ "$("$home/bin/warmbly" version)" == "warmbly v0.0.0-test (test)" ]] || fail "the installed binary does not run"
pass "installs a working binary from a mirror"

grep -q 'warmbly CLI installer' "$home/.bash_profile" 2>/dev/null || grep -q 'warmbly CLI installer' "$home/.bashrc" 2>/dev/null \
  || fail "the installer did not put the install directory on PATH"
pass "puts the install directory on PATH"

[[ -f "$home/.local/share/bash-completion/completions/warmbly" ]] || fail "no bash completions were written"
pass "writes shell completions"

# A second run must not append the PATH line again.
HOME="$home" SHELL=/bin/bash sh "$SCRIPT" \
  --base-url "file://$mirror" --dir "$home/bin" --no-color >/dev/null 2>&1 \
  || fail "the second install run failed"
occurrences=$(grep -c 'warmbly CLI installer' "$home/.bash_profile" 2>/dev/null || true)
[[ "${occurrences:-0}" -le 1 ]] || fail "re-running appended the PATH line again ($occurrences times)"
pass "re-running is idempotent"

# A tampered archive must stop the install, not warn about it.
bad="$work/badmirror"
mkdir -p "$bad"
cp "$mirror/$asset" "$bad/"
sed 's/^[0-9a-f]\{64\}/0000000000000000000000000000000000000000000000000000000000000000/' \
  "$mirror/checksums.txt" > "$bad/checksums.txt"
badhome="$work/badhome"
if HOME="$badhome" sh "$SCRIPT" --base-url "file://$bad" --dir "$badhome/bin" --no-color >/dev/null 2>&1; then
  fail "a checksum mismatch did not stop the install"
fi
[[ ! -e "$badhome/bin/warmbly" ]] || fail "a checksum mismatch still installed the binary"
pass "refuses to install on a checksum mismatch"

# --uninstall removes what it wrote, and leaves the credentials alone.
mkdir -p "$home/.config/warmbly"
echo "token" > "$home/.config/warmbly/hosts.yml"
HOME="$home" SHELL=/bin/bash sh "$SCRIPT" --uninstall --dir "$home/bin" --no-color >/dev/null 2>&1 \
  || fail "--uninstall failed"
[[ ! -e "$home/bin/warmbly" ]] || fail "--uninstall left the binary behind"
[[ ! -e "$home/.local/share/bash-completion/completions/warmbly" ]] || fail "--uninstall left completions behind"
[[ -f "$home/.config/warmbly/hosts.yml" ]] || fail "--uninstall removed the credentials; it must not"
pass "--uninstall removes the binary and completions, and keeps credentials"

# ─────────────────────────────────────────────────────────────────────────
# The Windows half. Ubuntu runners ship pwsh, so this is a real parse there.
# ─────────────────────────────────────────────────────────────────────────

if command -v pwsh >/dev/null 2>&1; then
  pwsh -NoProfile -Command "
    \$errors = \$null
    [System.Management.Automation.Language.Parser]::ParseFile('$PWD/$PS_SCRIPT', [ref]\$null, [ref]\$errors) | Out-Null
    if (\$errors) { \$errors | ForEach-Object { Write-Host \$_ }; exit 1 }
  " || fail "$PS_SCRIPT does not parse as PowerShell"
  pass "cli.ps1 parses as PowerShell"
else
  echo "· pwsh not installed; skipped the PowerShell parse"
fi

# ─────────────────────────────────────────────────────────────────────────
# The published checksum, which is what makes "download, verify, read, run" a
# real alternative to piping into a shell.
# ─────────────────────────────────────────────────────────────────────────

[[ -f $SUMFILE ]] || fail "$SUMFILE is missing. Run: make cli-sha"
( cd site/public && sha256_verify "$(basename "$SUMFILE")" >/dev/null ) \
  || fail "$SUMFILE does not match $SCRIPT. Run: make cli-sha"
pass "published checksum matches"

printf '\n\033[32mAll CLI installer checks passed.\033[0m\n'
