#!/bin/sh
# Installs Lumi by Loomtable, or updates it in place.
#
#   curl -fsSL https://lumi.loomtable.com/install.sh | sh
#
# What it does, in order:
#   1. Checks for macOS 26 or later on Apple Silicon.
#   2. Downloads Lumi.zip and Lumi.zip.sha256 from the latest GitHub release (loomtable/lumi).
#   3. Checks the SHA-256, and that the app is signed with the Loomtable Release certificate.
#   4. Quits Lumi if it's running (asks it to quit; never forces it), then replaces
#      /Applications/Lumi.app. It uses sudo only if you can't write to /Applications.
# It never opens Lumi. Your settings, conversations and permissions stay.
#
# Lumi isn't signed with an Apple Developer ID yet. Files downloaded with curl aren't
# quarantined, so macOS doesn't stop the first launch the way it does for a browser download.
set -eu

base=${LUMI_BASE_URL:-https://github.com/loomtable/lumi/releases/latest/download}
dest=${LUMI_INSTALL_DIR:-/Applications}
# The root of the "Loomtable Release" certificate every release is signed with.
cert_root=40f70adbae217403f3d16c860d8904424c281db2

fail() { echo "Lumi install: $*" >&2; exit 1; }

[ "$(uname -s)" = Darwin ] || fail "Lumi is a Mac app; this needs macOS 26 or later."
major=$(sw_vers -productVersion | cut -d. -f1)
[ "$major" -ge 26 ] || fail "Lumi needs macOS 26 or later; this Mac has $(sw_vers -productVersion)."
[ "$(sysctl -n hw.optional.arm64 2>/dev/null)" = 1 ] || fail "Lumi needs a Mac with Apple Silicon."

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT INT TERM

echo "Downloading Lumi..."
curl -fsSL --proto '=https,file' -o "$tmp/Lumi.zip" "$base/Lumi.zip" || fail "couldn't download $base/Lumi.zip"
curl -fsSL --proto '=https,file' -o "$tmp/Lumi.zip.sha256" "$base/Lumi.zip.sha256" || fail "couldn't download $base/Lumi.zip.sha256"

want=$(cut -d' ' -f1 "$tmp/Lumi.zip.sha256")
got=$(shasum -a 256 "$tmp/Lumi.zip" | cut -d' ' -f1)
[ -n "$want" ] && [ "$want" = "$got" ] || fail "the download doesn't match its SHA-256 checksum. Nothing was installed."

ditto -x -k "$tmp/Lumi.zip" "$tmp/x"
app="$tmp/x/Lumi.app"
codesign --verify --deep --strict "$app" 2>/dev/null || fail "Lumi.app's signature doesn't verify. Nothing was installed."
codesign -d -r- "$app" 2>&1 | grep -q "H\"$cert_root\"" || fail "Lumi.app isn't signed with the Loomtable Release certificate. Nothing was installed."
version=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist")

# Quit the copy we're replacing, the way its own Quit does, and wait for it.
if pgrep -f "^$dest/Lumi.app/Contents/MacOS/Lumi" >/dev/null; then
  echo "Quitting Lumi..."
  osascript -e 'tell application id "com.loomtable.lumi" to quit' >/dev/null 2>&1 || true
  i=0
  while pgrep -f "^$dest/Lumi.app/Contents/MacOS/Lumi" >/dev/null; do
    i=$((i + 1))
    [ "$i" -le 20 ] || fail "Lumi is still running. Quit it from its menu-bar menu, then run this again."
    sleep 0.5
  done
fi

[ -d "$dest" ] || mkdir -p "$dest" 2>/dev/null || true
sudo=
if [ ! -w "$dest" ] || { [ -e "$dest/Lumi.app" ] && [ ! -w "$dest/Lumi.app" ]; }; then
  echo "Your account can't write to $dest, so this step needs an administrator password."
  echo "(To install just for you instead: curl -fsSL https://lumi.loomtable.com/install.sh | LUMI_INSTALL_DIR=~/Applications sh)"
  sudo=sudo
fi

# Copy next to the old app first, so a failed copy never leaves you without Lumi.
$sudo rm -rf "$dest/.Lumi.app.new"
$sudo ditto "$app" "$dest/.Lumi.app.new"
$sudo rm -rf "$dest/Lumi.app"
$sudo mv "$dest/.Lumi.app.new" "$dest/Lumi.app"

echo "Lumi $version is installed in $dest."
echo "Next: open Lumi from $dest or Spotlight. Onboarding walks you through the key, permissions and voice."
