#!/usr/bin/env bash
# SubSpeech macOS installer / uninstaller.
#
# Hosted at Supabase Storage and run as a one-liner:
#   curl -fsSL <bucket>/distribution/macos/install.sh | bash                       # clean install (default)
#   curl -fsSL <bucket>/distribution/macos/install.sh | bash -s -- install         # install without wiping data
#   curl -fsSL <bucket>/distribution/macos/install.sh | bash -s -- uninstall
#   curl -fsSL <bucket>/distribution/macos/install.sh | bash -s -- reset-permissions
#
# The DEFAULT one-liner performs a CLEAN install: it quits SubSpeech and its
# helpers (the sabi-sidecar runtime and the native fn-key-listener), removes any
# existing /Applications/SubSpeech.app, wipes SubSpeech user data, and deletes
# Camera/Microphone/Input-Monitoring/Accessibility/Automation grants (including
# stale path-keyed Input Monitoring rows), then downloads the DMG
# named in the hosted manifest, installs SubSpeech.app into /Applications, and
# strips the macOS quarantine attribute. The build is currently unsigned, so the
# first launch may still need a right-click -> Open. Pass `install` explicitly to
# upgrade in place without wiping user data, or add `--skip-user-data` /
# `--skip-tcc-reset` to keep data or permission grants during a clean install.
#
# This dispatcher is intentionally thin. The real work lives in lib/*.sh, which
# are loaded from disk when the script is run from a repo checkout, or fetched
# from the same hosted bucket when the script is piped through curl.
set -euo pipefail

# Base URL for the hosted lib/*.sh modules. Override with SUBSPEECH_DIST_BASE_URL
# (e.g. for staging buckets or local testing). Must NOT end with a slash.
DEFAULT_DIST_BASE_URL="https://copcolowpilpcwgurbjn.supabase.co/storage/v1/object/public/distribution/macos"
DIST_BASE_URL="${SUBSPEECH_DIST_BASE_URL:-$DEFAULT_DIST_BASE_URL}"

LIB_MODULES=(common paths tcc keyboard install uninstall)

# Resolve the directory containing this script when run from disk. When the
# script is piped through `curl | bash` there is no real path, so this stays
# empty and we fall back to fetching libs over the network.
script_dir() {
  local src="${BASH_SOURCE[0]:-}"
  if [[ -z "$src" || "$src" == "bash" || "$src" == "-" ]]; then
    return 0
  fi
  ( cd "$(dirname "$src")" >/dev/null 2>&1 && pwd ) || true
}

load_libs() {
  local dir
  dir="$(script_dir)"
  if [[ -n "$dir" && -d "${dir}/lib" ]]; then
    local module
    for module in "${LIB_MODULES[@]}"; do
      # shellcheck source=/dev/null
      source "${dir}/lib/${module}.sh"
    done
    return 0
  fi

  # Piped execution: fetch each module from the hosted bucket and source it.
  if ! command -v curl >/dev/null 2>&1; then
    printf 'error: curl is required to run the hosted installer.\n' >&2
    exit 1
  fi
  local module contents
  for module in "${LIB_MODULES[@]}"; do
    if ! contents="$(curl -fsSL "${DIST_BASE_URL}/lib/${module}.sh")"; then
      printf 'error: failed to fetch installer module: %s/lib/%s.sh\n' "$DIST_BASE_URL" "$module" >&2
      exit 1
    fi
    # shellcheck source=/dev/null
    source /dev/stdin <<<"$contents"
  done
}

usage() {
  cat <<'EOF'
SubSpeech macOS installer

Usage: install.sh [command] [options]

Commands:
  clean-install        Wipe app + data + permissions, then fresh install (default)
  install              Download and install into /Applications without wiping data
  uninstall            Quit, remove the app, user data, and delete permissions
  reset-permissions    Delete Camera/Microphone/Input Monitoring/Accessibility/Automation
  help                 Show this help

Options:
  --dry-run            Print actions without changing anything
  --arch <arm64|x64>   Force the DMG architecture; default auto-detects this Mac
  --dmg-url <url>      Install a specific DMG (URL, file://, or local path);
                       skips the hosted manifest lookup
  --launch             Open SubSpeech after a successful install (default)
  --no-launch          Do not open SubSpeech after install
  --skip-user-data     (uninstall/clean-install) Keep ~/Library data
  --skip-tcc-reset     (uninstall/clean-install) Keep existing permission grants

Environment:
  SUBSPEECH_MANIFEST_URL    Override the manifest URL
  SUBSPEECH_DIST_BASE_URL   Override the base URL for hosted lib modules
EOF
}

main() {
  local command=""
  DRY_RUN=0
  # Open the app after a successful install by default; --no-launch opts out.
  LAUNCH_AFTER=1
  SKIP_USER_DATA=0
  SKIP_TCC_RESET=0
  INSTALL_ARCH="${INSTALL_ARCH:-}"
  DMG_URL="${DMG_URL:-}"

  while [[ $# -gt 0 ]]; do
    case "$1" in
      install|uninstall|clean-install|reset-permissions|help)
        command="$1"
        ;;
      --dry-run) DRY_RUN=1 ;;
      --launch) LAUNCH_AFTER=1 ;;
      --no-launch) LAUNCH_AFTER=0 ;;
      --skip-user-data) SKIP_USER_DATA=1 ;;
      --skip-tcc-reset) SKIP_TCC_RESET=1 ;;
      --arch)
        shift
        INSTALL_ARCH="${1:-}"
        case "$INSTALL_ARCH" in
          arm64|x64) ;;
          *) printf 'error: --arch must be arm64 or x64\n' >&2; exit 2 ;;
        esac
        ;;
      --dmg-url)
        shift
        DMG_URL="${1:-}"
        [[ -n "$DMG_URL" ]] || { printf 'error: --dmg-url requires a value\n' >&2; exit 2; }
        ;;
      -h|--help) command="help" ;;
      *)
        printf 'error: unknown argument: %s\n' "$1" >&2
        usage >&2
        exit 2
        ;;
    esac
    shift
  done

  export DRY_RUN LAUNCH_AFTER SKIP_USER_DATA SKIP_TCC_RESET INSTALL_ARCH DMG_URL

  if [[ "$command" == "help" ]]; then
    usage
    return 0
  fi

  load_libs

  case "${command:-clean-install}" in
    install) do_install ;;
    uninstall) do_uninstall ;;
    clean-install) do_clean_install ;;
    reset-permissions) reset_permissions ;;
  esac
}

main "$@"
