#!/bin/sh
set -eu
usage() {
  cat <<'HELP'
Trellis Mac companion installer

Connect this Mac's browser to development servers on your VM.

Usage:
  curl -fsSL https://companion.trellistech.com | sh
  curl -fsSL https://companion.trellistech.com | sh -s -- --verbose

Options:
  --verbose  stream tool output as it runs (all output is always logged)
  --help     show this help and exit
HELP
}
verbose=0
for arg in "$@"; do
  case "$arg" in
    --verbose) verbose=1 ;;
    --help) usage; exit 0 ;;
    *) echo "Unknown option: $arg" >&2; usage >&2; exit 2 ;;
  esac
done
umask 077
companion_root="${TRELLIS_COMPANION_HOME:-$HOME/.local/share/trellis/mac-companion}"
companion_origin="${TRELLIS_COMPANION_ORIGIN:-https://companion.trellistech.com}"
case "$companion_root" in /*) ;; *) echo 'TRELLIS_COMPANION_HOME must be an absolute path.' >&2; exit 1 ;; esac
case "$companion_origin" in https://*) ;; *) echo 'The companion download origin must use HTTPS.' >&2; exit 1 ;; esac
if [ "$(uname -s)" != Darwin ]; then echo 'This installer requires macOS. Run it in a terminal on your Mac.' >&2; exit 1; fi
mkdir -p "$companion_root/logs"
started_at=$(date +%s)
installer_log="$companion_root/logs/install-$(date -u +%Y%m%dT%H%M%SZ)-$$.log"
touch "$installer_log"
installer_tmp=$(mktemp -d "$companion_root/.install.XXXXXX")
exec 3>&1 4>&2
cleanup() {
  status=$?
  trap - EXIT HUP INT TERM
  elapsed=$(( $(date +%s) - started_at ))
  exec 1>&3 2>&4
  if [ "$status" -ne 0 ]; then printf '[Trellis] Failed after %ss (exit %s). Full log: %s\n' "$elapsed" "$status" "$installer_log" >&2; fi
  rm -rf "$installer_tmp"
  exit "$status"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' HUP TERM
log() { printf '%s\n' "$*" >>"$installer_log"; }
say() { printf '[Trellis] %s\n' "$*" >&3; log "[info] $*"; }
run_logged() {
  label=$1; shift
  say "$label"
  output="$installer_tmp/command-output"
  : >"$output"
  if "$@" >"$output" 2>&1; then :; else
    status=$?
    cat "$output" >>"$installer_log"
    if [ "$verbose" -eq 1 ]; then cat "$output" >&3; fi
    printf '[Trellis] Last output from %s:\n' "$label" >&3
    tail -n 8 "$output" >&3
    say "$label failed (exit $status). See $installer_log"
    return "$status"
  fi
  cat "$output" >>"$installer_log"
  if [ "$verbose" -eq 1 ]; then cat "$output" >&3; fi
}
say 'Trellis Mac companion installer'
say "Purpose: connect this Mac's browser to development servers on your VM."
say "Install directory: $companion_root"
say "Installer log: $installer_log"
say "Download origin: $companion_origin"
say '[1/4] Mac: download and verify companion'
for artifact in setup.mjs worker.mjs SHA256SUMS; do
  run_logged "Downloading $artifact" curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 --connect-timeout 15 --max-time 180 --retry 2 "${companion_origin%/}/companion/$artifact" --output "$installer_tmp/$artifact"
done
run_logged 'Verifying downloaded checksums' sh -c 'cd "$1"; for artifact in setup.mjs worker.mjs; do expected=$(awk -v file="$artifact" '\''$2 == file { print $1 }'\'' SHA256SUMS); actual=$(shasum -a 256 "$artifact" | awk '\''{ print $1 }'\''); [ -n "$expected" ] && [ "$expected" = "$actual" ] || { echo "Checksum verification failed for $artifact" >&2; exit 1; }; done' sh "$installer_tmp"
node_path=$(command -v node || true)
gcloud_path=$(command -v gcloud || true)
if [ -n "$node_path" ] && ! "$node_path" -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 22 ? 0 : 1)' >/dev/null 2>&1; then node_path=''; fi
say '[2/4] Mac: prepare runtime tools (Node 22+ and Google Cloud CLI)'
if [ -z "$node_path" ] || [ -z "$gcloud_path" ]; then
  if ! command -v mise >/dev/null 2>&1; then
    if [ -x "$HOME/.local/bin/mise" ]; then PATH="$HOME/.local/bin:$PATH"; export PATH; else
      run_logged 'Installing mise' sh -c 'curl --fail --silent --show-error --location --proto "=https" --tlsv1.2 https://mise.run | MISE_INSTALL_PATH="$1" sh' sh "$HOME/.local/bin/mise"
      PATH="$HOME/.local/bin:$PATH"; export PATH
    fi
  fi
  mkdir -p "$companion_root/toolchain"
  printf '[tools]\nnode = "24"\ngcloud = "latest"\n' >"$companion_root/toolchain/mise.toml"
  (cd "$companion_root/toolchain" && mise trust --yes "$companion_root/toolchain/mise.toml") >>"$installer_log" 2>&1
  if [ -z "$node_path" ]; then run_logged 'Installing Node 24 with mise' mise install node@24; node_path=$(mise which node --tool=node@24); else say "Reusing Node: $node_path"; fi
  if [ -z "$gcloud_path" ]; then run_logged 'Installing Google Cloud CLI with mise' mise install gcloud@latest; gcloud_path=$(mise which gcloud --tool=gcloud@latest); else say "Reusing Google Cloud CLI: $gcloud_path"; fi
else
  say "Reusing Node: $node_path"
  say "Reusing Google Cloud CLI: $gcloud_path"
fi
say '[3/4] Mac: install companion programs'
mv "$installer_tmp/setup.mjs" "$companion_root/setup.mjs"
mv "$installer_tmp/worker.mjs" "$companion_root/worker.mjs"
mv "$installer_tmp/SHA256SUMS" "$companion_root/SHA256SUMS"
say '[4/4] Mac -> VM: connect browser bridge'
node_output="$installer_tmp/setup-output"
node_fifo="$installer_tmp/setup-output.fifo"
mkfifo "$node_fifo"
tee -a "$installer_log" < "$node_fifo" >&3 &
node_tee=$!
set +e
if ( : < /dev/tty ) 2>/dev/null; then
  "$node_path" "$companion_root/setup.mjs" --gcloud "$gcloud_path" --node "$node_path" --worker "$companion_root/worker.mjs" < /dev/tty > "$node_fifo" 2>&1
else
  "$node_path" "$companion_root/setup.mjs" --gcloud "$gcloud_path" --node "$node_path" --worker "$companion_root/worker.mjs" < /dev/null > "$node_fifo" 2>&1
fi
node_status=$?
set -e
wait "$node_tee" || true
rm -f "$node_fifo"
if [ "$node_status" -ne 0 ]; then
  say "Bridge setup failed (exit $node_status). See $installer_log"
  exit "$node_status"
fi
elapsed=$(( $(date +%s) - started_at ))
say "Connected. Companion directory: $companion_root"
say "Check command: $node_path $companion_root/setup.mjs --check"
say "Runtime log: $HOME/.local/state/trellis/mac-companion/service.log"
say "Completed in ${elapsed}s. Installer log: $installer_log"
