#!/bin/zsh

# Swipe Bridge launcher for macOS.
#
# This file never pipes downloaded data into a shell. It either runs a bridge
# executable shipped beside it or downloads a versioned release archive,
# verifies its SHA-256 checksum, extracts it into the current user's cache, and
# runs that verified executable.

set -eu
set -o pipefail

SWIPE_RELEASE_BASE_URL="${SWIPE_BRIDGE_RELEASE_BASE_URL:-https://swipe.surajgavali.com/downloads}"
SWIPE_LAUNCHER_DIR="${0:A:h}"
SWIPE_TEMP_DIR=""

swipe_cleanup() {
  if [[ -n "$SWIPE_TEMP_DIR" && -d "$SWIPE_TEMP_DIR" ]]; then
    /bin/rm -rf -- "$SWIPE_TEMP_DIR"
  fi
}

swipe_fail() {
  print -u2 -- "Swipe Bridge: $1"
  exit 1
}

swipe_usage() {
  cat <<'EOF'
Swipe Bridge launcher for macOS

Usage:
  Open this file and choose a folder when prompted. If the browser did not
  preserve executable permission, open Terminal and run:
  zsh "$HOME/Downloads/swipe-bridge-macos.command"

  To choose the folder on the command line, run:
  ./swipe-bridge-macos.command "/Volumes/Your Drive/Photos"

Optional environment variable:
  SWIPE_BRIDGE_RELEASE_BASE_URL=https://example.com/releases/latest/download

The launcher does not install Dart, Homebrew, FFmpeg, or any other dependency.
EOF
}

trap swipe_cleanup EXIT INT TERM

if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
  swipe_usage
  exit 0
fi
if (( $# > 1 )); then
  swipe_usage >&2
  exit 64
fi

case "$SWIPE_RELEASE_BASE_URL" in
  https://*) ;;
  *) swipe_fail "The release download address must use HTTPS." ;;
esac

swipe_sha256() {
  /usr/bin/shasum -a 256 -- "$1" | /usr/bin/awk '{print tolower($1)}'
}

swipe_verify_binary_manifest() {
  local binary_path="$1"
  local manifest_path="$2"
  [[ -f "$binary_path" && -f "$manifest_path" ]] || return 1

  local expected
  expected=$(/usr/bin/awk '
    $1 ~ /^[0-9a-fA-F]{64}$/ {
      name = $2
      sub(/^\*/, "", name)
      if (name == "swipe-bridge") {
        print tolower($1)
      }
    }
  ' "$manifest_path")
  [[ ${#expected} -eq 64 && "$expected" != *[^0-9a-f]* ]] || return 1
  [[ "$(swipe_sha256 "$binary_path")" == "$expected" ]]
}

swipe_find_colocated_bridge() {
  local candidate
  for candidate in \
    "$SWIPE_LAUNCHER_DIR/swipe-bridge" \
    "$SWIPE_LAUNCHER_DIR/Swipe Bridge/swipe-bridge"; do
    if [[ -f "$candidate" && -x "$candidate" ]]; then
      local manifest="${candidate:h}/BINARY_SHA256"
      if [[ -f "$manifest" ]] && ! swipe_verify_binary_manifest "$candidate" "$manifest"; then
        swipe_fail "The bridge beside this launcher failed its checksum check. Download a fresh package."
      fi
      print -r -- "$candidate"
      return 0
    fi
  done
  return 1
}

swipe_download_bridge() {
  command -v curl >/dev/null 2>&1 || swipe_fail "macOS curl is required to download Swipe Bridge."
  [[ -x /usr/bin/shasum ]] || swipe_fail "macOS shasum is required to verify Swipe Bridge."
  [[ -x /usr/bin/unzip ]] || swipe_fail "macOS unzip is required to open the verified package."

  local machine_arch release_arch
  machine_arch=$(/usr/bin/uname -m)
  case "$machine_arch" in
    arm64) release_arch="arm64" ;;
    x86_64) release_arch="x64" ;;
    *) swipe_fail "This Mac architecture is not supported: $machine_arch" ;;
  esac

  SWIPE_TEMP_DIR=$(/usr/bin/mktemp -d "${TMPDIR:-/tmp}/swipe-bridge.XXXXXXXX")
  local sums_path="$SWIPE_TEMP_DIR/SHA256SUMS"
  local sums_url="${SWIPE_RELEASE_BASE_URL%/}/SHA256SUMS"

  print -u2 -- "Checking the latest Swipe Bridge package…"
  /usr/bin/curl \
    --proto '=https' \
    --tlsv1.2 \
    --fail \
    --location \
    --silent \
    --show-error \
    --output "$sums_path" \
    "$sums_url" || swipe_fail \
      "Could not download release checksums. If the source repository is private, use a public release host or download the complete package instead."

  local suffix="-macos-${release_arch}.zip"
  local matching_lines
  matching_lines=$(/usr/bin/awk -v suffix="$suffix" '
    $1 ~ /^[0-9a-fA-F]{64}$/ {
      name = $2
      sub(/^\*/, "", name)
      if (name ~ /^swipe-bridge-[0-9A-Za-z._+-]+-macos-(arm64|x64)\.zip$/ &&
          length(name) >= length(suffix) &&
          substr(name, length(name) - length(suffix) + 1) == suffix) {
        print tolower($1) " " name
      }
    }
  ' "$sums_path")
  local match_count
  match_count=$(print -r -- "$matching_lines" | /usr/bin/awk 'NF { count += 1 } END { print count + 0 }')
  (( match_count == 1 )) || swipe_fail "The release checksum index does not contain exactly one package for this Mac."

  local expected_sha asset_name
  expected_sha="${matching_lines%% *}"
  asset_name="${matching_lines#* }"
  [[ ${#expected_sha} -eq 64 && "$expected_sha" != *[^0-9a-f]* ]] || swipe_fail "The release checksum is invalid."
  [[ "$asset_name" != */* && "$asset_name" != *\\* ]] || swipe_fail "The release package name is unsafe."

  local cache_parent cache_directory cached_bridge cached_manifest
  cache_parent="${HOME:?}/Library/Caches/Swipe Bridge"
  cache_directory="$cache_parent/${asset_name%.zip}"
  cached_bridge="$cache_directory/swipe-bridge"
  cached_manifest="$cache_directory/BINARY_SHA256"
  /bin/mkdir -p -- "$cache_parent"
  /bin/chmod 700 -- "$cache_parent"

  if [[ -x "$cached_bridge" ]]; then
    swipe_verify_binary_manifest "$cached_bridge" "$cached_manifest" || swipe_fail \
      "The cached bridge failed its checksum check. Remove '$cache_directory' and run this launcher again."
    print -r -- "$cached_bridge"
    return 0
  fi
  if [[ -e "$cache_directory" ]]; then
    swipe_fail "The bridge cache is incomplete. Remove '$cache_directory' and run this launcher again."
  fi

  local archive_path="$SWIPE_TEMP_DIR/$asset_name"
  local archive_url="${SWIPE_RELEASE_BASE_URL%/}/$asset_name"
  /usr/bin/curl \
    --proto '=https' \
    --tlsv1.2 \
    --fail \
    --location \
    --silent \
    --show-error \
    --output "$archive_path" \
    "$archive_url" || swipe_fail "Could not download $asset_name."

  [[ "$(swipe_sha256 "$archive_path")" == "$expected_sha" ]] || swipe_fail \
    "The downloaded package did not match its published SHA-256 checksum. Nothing was run."

  # Reject absolute paths, Windows separators, and parent traversal before the
  # verified archive is extracted.
  /usr/bin/unzip -Z1 "$archive_path" | /usr/bin/awk -F/ '
    /^\// || /\\/ { exit 1 }
    {
      for (index = 1; index <= NF; index += 1) {
        if ($index == "..") exit 1
      }
    }
  ' || swipe_fail "The release archive contains an unsafe path. Nothing was extracted."

  local extract_directory="$SWIPE_TEMP_DIR/extracted"
  /bin/mkdir -- "$extract_directory"
  /usr/bin/unzip -q "$archive_path" -d "$extract_directory"
  local package_directory="$extract_directory/Swipe Bridge"
  local extracted_bridge="$package_directory/swipe-bridge"
  local extracted_manifest="$package_directory/BINARY_SHA256"
  [[ -f "$extracted_bridge" && -f "$extracted_manifest" ]] || swipe_fail \
    "The release package is missing the Swipe Bridge executable or its checksum."
  /bin/chmod 700 -- "$extracted_bridge"
  swipe_verify_binary_manifest "$extracted_bridge" "$extracted_manifest" || swipe_fail \
    "The executable inside the package failed verification. Nothing was run."

  /bin/mv -- "$package_directory" "$cache_directory"
  /bin/chmod -R go-rwx -- "$cache_directory"
  print -r -- "$cached_bridge"
}

SWIPE_BRIDGE_PATH=""
if SWIPE_BRIDGE_PATH=$(swipe_find_colocated_bridge); then
  :
else
  SWIPE_BRIDGE_PATH=$(swipe_download_bridge)
fi

SWIPE_MEDIA_ROOT="${1:-}"
if [[ -z "$SWIPE_MEDIA_ROOT" ]]; then
  if [[ -x /usr/bin/osascript ]]; then
    SWIPE_MEDIA_ROOT=$(/usr/bin/osascript <<'APPLESCRIPT' || true
try
  return POSIX path of (choose folder with prompt "Choose the backed-up media folder or external drive to share with Swipe")
on error number -128
  return ""
end try
APPLESCRIPT
    )
  fi
fi
if [[ -z "$SWIPE_MEDIA_ROOT" ]]; then
  print -- "Drag a backed-up media folder or drive into this window, then press Return:"
  IFS= read -r SWIPE_MEDIA_ROOT
fi
[[ -n "$SWIPE_MEDIA_ROOT" ]] || swipe_fail "No media folder was selected."
[[ -d "$SWIPE_MEDIA_ROOT" ]] || swipe_fail "That folder or drive does not exist: $SWIPE_MEDIA_ROOT"

cat <<'EOF'

Swipe Bridge is about to start.

• Keep this window open while using Swipe.
• Keep the phone and Mac on the same trusted Wi-Fi or wired LAN.
• Avoid guest Wi-Fi, VPNs, and networks with device isolation.
• If macOS asks about incoming connections, choose Allow on private networks.
• Start with a backed-up test folder. Swipe stages files before any confirmed move.

The bridge will show the pairing code or pairing instructions below.
Press Control-C when you are finished.

EOF

swipe_cleanup
trap - EXIT INT TERM
exec "$SWIPE_BRIDGE_PATH" --root "$SWIPE_MEDIA_ROOT"
