#!/bin/sh
# Install the public Rex Architect Mac app. No account data or projects are changed.
set -eu

VERSION='0.9.8'
SHA256='f404e82ac9d93a53d16e36782d446be5014674d24a242e01c76c67f014a52bc7'
FILE="Rex-${VERSION}-macOS-arm64.zip"
URL="https://re-x.ai/downloads/${FILE}"
TEAM='U928CCRQ2N'
BUNDLE_ID='studio.rex.architect.development'
fail() { printf 'Rex installer: %s\n' "$*" >&2; exit 1; }

[ "$(uname -s)" = Darwin ] || fail 'This installer is for macOS.'
[ "$(uname -m)" = arm64 ] || fail 'Use an Apple Silicon Mac and a native Terminal session.'
os_version=$(sw_vers -productVersion)
os_major=${os_version%%.*}
case "$os_major" in *[!0-9]*|'') fail 'Could not read the macOS version.' ;; esac
[ "$os_major" -ge 15 ] || fail 'Rex Architect requires macOS 15 (Sequoia) or later.'
case "$SHA256" in *[!a-f0-9]*|'') fail 'This release is not ready for installation.' ;; esac
[ "${#SHA256}" -eq 64 ] || fail 'Invalid release checksum.'
for tool in curl shasum ditto codesign spctl plutil ps mktemp; do
  command -v "$tool" >/dev/null 2>&1 || fail "Required macOS tool is missing: $tool"
done

if [ -n "${REX_INSTALL_DIR:-}" ]; then
  install_dir=$REX_INSTALL_DIR
elif [ -w /Applications ]; then
  install_dir=/Applications
else
  install_dir="$HOME/Applications"
fi
case "$install_dir" in /*) ;; *) fail 'REX_INSTALL_DIR must be an absolute path.' ;; esac
mkdir -p "$install_dir"
install_dir=$(cd "$install_dir" && pwd -P)
[ -w "$install_dir" ] || fail "Cannot write to $install_dir"
target="$install_dir/Rex Architect.app"
[ ! -L "$target" ] || fail 'The destination app is a symbolic link. Choose another installation folder.'
if ps -axo comm= | (while IFS= read -r executable; do
  case "$executable" in "$target/Contents/"*) exit 0 ;; esac
done; exit 1); then
  fail 'Quit Rex Architect before updating it, then run this command again.'
fi
if [ -e "$target" ]; then
  [ -d "$target" ] || fail 'The destination exists and is not an app folder.'
  existing_id=$(plutil -extract CFBundleIdentifier raw -o - "$target/Contents/Info.plist")
  [ "$existing_id" = "$BUNDLE_ID" ] || fail 'The destination belongs to another app; it was left unchanged.'
fi

work=$(mktemp -d "${TMPDIR:-/tmp}/rex-download.XXXXXXXX")
stage=''
backup=''
restore_old=0
cleanup() {
  status=$?
  trap - EXIT HUP INT TERM
  if [ "$restore_old" -eq 1 ] && [ ! -e "$target" ] && [ -d "$backup" ]; then
    mv "$backup" "$target" || printf 'Your previous app is preserved at %s\n' "$backup" >&2
  fi
  rm -rf "$work"
  [ -z "$stage" ] || rm -rf "$stage"
  exit "$status"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' HUP TERM

printf 'Downloading Rex Architect %s…\n' "$VERSION"
curl --disable --fail --location --proto '=https' --proto-redir '=https' --tlsv1.2 \
  --retry 2 --connect-timeout 15 --max-time 900 --output "$work/$FILE" "$URL"
actual=$(shasum -a 256 "$work/$FILE")
actual=${actual%% *}
[ "$actual" = "$SHA256" ] || fail 'Download checksum mismatch. Your installed app was left unchanged.'
ditto -x -k "$work/$FILE" "$work/extracted"
app="$work/extracted/Rex Architect.app"
[ -d "$app" ] && [ ! -L "$app" ] || fail 'The archive does not contain the expected app.'
[ "$(plutil -extract CFBundleIdentifier raw -o - "$app/Contents/Info.plist")" = "$BUNDLE_ID" ] || fail 'Unexpected app identity.'
[ "$(plutil -extract CFBundleShortVersionString raw -o - "$app/Contents/Info.plist")" = "$VERSION" ] || fail 'Unexpected app version.'
codesign --verify --deep --strict "$app"
signature=$(codesign -dv --verbose=4 "$app" 2>&1)
printf '%s\n' "$signature" | grep -qx "TeamIdentifier=$TEAM" || fail 'Unexpected Developer ID team.'
spctl --assess --type execute "$app"

# Verify the staged copy before replacing anything. A failed rename restores the old app.
stage=$(mktemp -d "$install_dir/.rex-install.XXXXXXXX")
ditto "$app" "$stage/Rex Architect.app"
codesign --verify --deep --strict "$stage/Rex Architect.app"
if [ -e "$target" ]; then
  backup="$install_dir/.Rex Architect.backup-$(date +%Y%m%d%H%M%S)-$$.app"
  [ ! -e "$backup" ] || fail 'Backup destination is already in use.'
  mv "$target" "$backup"
  restore_old=1
fi
mv "$stage/Rex Architect.app" "$target"
restore_old=0
printf 'Installed Rex Architect %s at %s\n' "$VERSION" "$target"
[ -z "$backup" ] || printf 'Previous app preserved at %s\n' "$backup"
if [ "${REX_OPEN_APP:-1}" != 0 ]; then
  open "$target" || printf 'Open Rex Architect from Applications to get started.\n'
fi
