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

Prepare your VM checkout, SSH host, and persistent browser bridge.

Usage:
  curl -fsSL https://remote-dev.trellistech.com | sh
  curl -fsSL https://remote-dev.trellistech.com | sh -s -- --verbose
  trellis-companion uninstall

Options:
  --verbose  stream tool output as it runs (all output is always logged)
  uninstall  remove the companion, LaunchAgent, state, logs, and launcher
  --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"
  set +e
  "$@" >"$output" 2>&1 &
  command_pid=$!
  command_started_at=$(date +%s)
  (
    stop_progress() {
      kill "$sleep_pid" 2>/dev/null || true
      exit 0
    }
    trap stop_progress TERM INT HUP
    while kill -0 "$command_pid" 2>/dev/null; do
      sleep 1 &
      sleep_pid=$!
      wait "$sleep_pid"
      if kill -0 "$command_pid" 2>/dev/null; then
        command_elapsed=$(( $(date +%s) - command_started_at ))
        if [ "$command_elapsed" -ge 5 ] && [ $((command_elapsed % 5)) -eq 0 ]; then
          say "$label still running (${command_elapsed}s elapsed). Output is being recorded in $installer_log"
        fi
      fi
    done
  ) &
  progress_pid=$!
  wait "$command_pid"
  status=$?
  kill "$progress_pid" 2>/dev/null || true
  set -e
  if [ "$status" -ne 0 ]; then
    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 remote development installer'
say "Purpose: prepare your VM checkout, SSH connection, and browser bridge."
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
    say 'The gcloud installer may ask for your Mac administrator password. This is a local macOS permission prompt, not a Google Cloud password.'
    run_logged 'Installing Google Cloud CLI with mise' mise install gcloud@latest
    gcloud_path=$(mise which gcloud --tool=gcloud@latest)
  fi
  say "Reusing Google Cloud CLI: $gcloud_path"
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"
launcher_dir="$HOME/.local/bin"
launcher="$launcher_dir/trellis-companion"
mkdir -p "$launcher_dir"
launcher_tmp="$installer_tmp/trellis-companion"
cat >"$launcher_tmp" <<LAUNCHER
#!/bin/sh
# Trellis Mac companion launcher
if [ "\${1:-}" = uninstall ]; then
  shift
  set -- --uninstall "\$@"
fi
exec "$node_path" "$companion_root/setup.mjs" "\$@" --gcloud "$gcloud_path" --node "$node_path" --worker "$companion_root/worker.mjs"
LAUNCHER
chmod 755 "$launcher_tmp"
mv "$launcher_tmp" "$launcher"
say "Command installed: trellis-companion (from $launcher)"
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 "SSH host: trellis-remote-dev (open ~/trellis on the VM)"
say "Check command: trellis-companion status"
say "Repair command: trellis-companion repair"
case ":$PATH:" in
  *":$launcher_dir:"*) ;;
  *) say "Add the CLI to your shell: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;;
esac
say "Runtime log: $HOME/.local/state/trellis/mac-companion/service.log"
say "Completed in ${elapsed}s. Installer log: $installer_log"
