#!/usr/bin/env bash
set -euo pipefail

# install-macos-bestcodex.sh
#
# Installs Bestcodex Desktop from a ZIP that sits next to this script.
# Download BOTH this script and Bestcodex-Desktop-<version>-mac-arm64.zip from
# the same download folder into one place (e.g. ~/Downloads), then run:
#
#   bash install-macos-bestcodex.sh
#
# Why this exists: the build is signed with an Apple Development identity and is
# not notarized, so macOS quarantines a browser download and Gatekeeper refuses
# the first launch. If the user clicks through anyway, macOS runs the app from a
# read-only AppTranslocation copy, where Squirrel cannot replace the bundle and
# in-app updates can never install. Clearing com.apple.quarantine on a copy in
# /Applications is what makes the install stable and updatable.
#
# Usage:
#   bash install-macos-bestcodex.sh                      # auto-pick the ZIP next to this script
#   bash install-macos-bestcodex.sh /path/to/Bestcodex-Desktop-0.1.6-mac-arm64.zip
#   bash install-macos-bestcodex.sh --no-open <zip>      # install without launching

APP_NAME="Bestcodex Desktop.app"
APP_PATH="/Applications/${APP_NAME}"
EXPECTED_BUNDLE_ID="xyz.bestcodex.desktop"

say() { printf '%s\n' "$*"; }
fail() { printf 'error: %s\n' "$*" >&2; exit 1; }

script_dir() {
  cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1
  pwd
}

find_zip() {
  local dir="$1" wanted arch
  arch="$(uname -m)"
  case "$arch" in
    arm64) wanted="arm64" ;;
    x86_64) wanted="x64" ;;
    *) fail "unsupported architecture: $arch (this installer handles arm64 and x64 macOS builds)" ;;
  esac

  shopt -s nullglob
  local matches=("${dir}"/Bestcodex-Desktop-*-mac-*.zip)
  shopt -u nullglob

  if [ "${#matches[@]}" -eq 0 ]; then
    return 1
  fi

  if [ "${#matches[@]}" -eq 1 ]; then
    printf '%s\n' "${matches[0]}"
    return 0
  fi

  local zip
  for zip in "${matches[@]}"; do
    if [[ "$(basename "$zip")" == *"-mac-${wanted}.zip" ]]; then
      printf '%s\n' "$zip"
      return 0
    fi
  done

  printf '%s\n' "${matches[0]}"
}

# Pick the newest version when the folder holds several downloads.
newest_of() {
  printf '%s\n' "$@" | sort -V | tail -n 1
}

main() {
  local open_after=1
  local zip=""

  while [ "$#" -gt 0 ]; do
    case "$1" in
      --no-open) open_after=0; shift ;;
      -h|--help)
        sed -n '4,30p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
        exit 0
        ;;
      --*) fail "unknown option: $1" ;;
      *) zip="$1"; shift ;;
    esac
  done

  if [ -z "$zip" ]; then
    local candidates
    if ! candidates="$(find_zip "$(script_dir)")"; then
      fail "no Bestcodex-Desktop-*-mac-*.zip found next to this script. Download the ZIP into the same folder as this script, then run it again."
    fi
    # shellcheck disable=SC2086
    zip="$(newest_of $candidates)"
  fi

  [ -f "$zip" ] || fail "zip not found: $zip"

  say "Using archive: $zip"

  # Must not be `local`: the EXIT trap runs after main() returns, where a local
  # would already be out of scope and `set -u` would abort the trap.
  WORKDIR="$(mktemp -d "${TMPDIR:-/tmp}/bestcodex-install.XXXXXX")"
  trap 'rm -rf "$WORKDIR" 2>/dev/null || true' EXIT
  local workdir="$WORKDIR"

  # Unpack first, so a corrupted download fails before the existing app is touched.
  say "Verifying archive..."
  ditto -x -k "$zip" "$workdir" || fail "could not extract $zip (the download may be incomplete; re-download and try again)"

  local staged="${workdir}/${APP_NAME}"
  [ -d "$staged" ] || fail "archive does not contain ${APP_NAME}"

  local staged_id
  staged_id="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "${staged}/Contents/Info.plist" 2>/dev/null || true)"
  [ "$staged_id" = "$EXPECTED_BUNDLE_ID" ] \
    || fail "archive contains an unexpected app (bundle id: ${staged_id:-missing}); refusing to install"

  local version
  version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "${staged}/Contents/Info.plist" 2>/dev/null || true)"
  say "Archive version: ${version:-unknown}"

  say "Quitting any running ${APP_NAME}..."
  osascript -e "tell application \"Bestcodex Desktop\" to quit" >/dev/null 2>&1 || true
  # Translocation copies are read-only; the running process has to go before the
  # real bundle can be replaced.
  sleep 2
  pkill -f "${APP_NAME}/Contents/MacOS/Bestcodex Desktop" >/dev/null 2>&1 || true
  sleep 1

  if [ -d "$APP_PATH" ]; then
    local backup="${HOME}/.Trash/Bestcodex Desktop.$(date +%Y%m%d%H%M%S).app"
    say "Moving the installed copy to: $backup"
    mv "$APP_PATH" "$backup" || fail "could not move the existing app aside; close it and try again"
  fi

  say "Installing to: $APP_PATH"
  ditto "$staged" "$APP_PATH" || fail "could not write ${APP_PATH}"

  # The whole point of the script: without this the app runs translocated and
  # can never update itself.
  xattr -dr com.apple.quarantine "$APP_PATH" 2>/dev/null || true
  xattr -dr com.apple.quarantine "$zip" 2>/dev/null || true

  local remaining
  remaining="$(xattr "$APP_PATH" 2>/dev/null | grep -c '^com\.apple\.quarantine$' || true)"
  if [ "${remaining:-0}" -gt 0 ]; then
    say "warning: com.apple.quarantine is still present on ${APP_PATH}; in-app updates may fail."
  fi

  say "Installed ${APP_NAME} ${version:-} at ${APP_PATH}"

  if [ "$open_after" -eq 1 ]; then
    say "Opening Bestcodex Desktop..."
    open "$APP_PATH" || fail "installed, but could not launch the app; open it from /Applications"
  else
    say "Not launching (--no-open)."
  fi
}

main "$@"
