#!/usr/bin/env bash
#
# Sendwire installer — curl -fsSL https://sendwire.dev/install.sh | bash
#
# Modelled on Claude Code's bootstrap: detect the platform, resolve the latest
# release from a manifest, verify a SHA-256, install, and put the CLI on PATH.
# The difference is what gets installed — Sendwire is a GUI app, not a single
# binary — so macOS drops Sendwire.app into /Applications and Linux installs an
# AppImage. Either way the `sendwire` / `sw` commands land in ~/.local/bin.
#
# Overrides (env):
#   SENDWIRE_BASE_URL   release host (default below)
#   SENDWIRE_VERSION    pin a version instead of latest
#   SENDWIRE_INSTALL_DIR  where the .app / AppImage goes (default /Applications or ~/Applications)
#
set -euo pipefail

BASE_URL="${SENDWIRE_BASE_URL:-https://downloads.sendwire.dev}"
BIN_DIR="${HOME}/.local/bin"

say()  { printf '\033[1m%s\033[0m\n' "$*"; }
info() { printf '  %s\n' "$*"; }
err()  { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }

# --- refuse sudo from a normal user's shell (would install into /root) --------
if [ "${EUID:-$(id -u)}" = "0" ] && [ -z "${SENDWIRE_ALLOW_ROOT:-}" ]; then
  err "Don't run this with sudo — it installs into your home. Re-run as yourself."
fi

# --- a downloader -------------------------------------------------------------
if command -v curl >/dev/null 2>&1; then
  dl() { curl -fsSL "$1"; }
  dlo() { curl -fsSL "$1" -o "$2"; }
elif command -v wget >/dev/null 2>&1; then
  dl() { wget -qO- "$1"; }
  dlo() { wget -qO "$2" "$1"; }
else
  err "Need curl or wget."
fi

# --- platform: os-arch --------------------------------------------------------
os="$(uname -s)"; arch="$(uname -m)"
case "$os" in
  Darwin) os="darwin" ;;
  Linux)  os="linux" ;;
  MINGW*|MSYS*|CYGWIN*)
    say "Sendwire on Windows"
    info "Run this in PowerShell instead:"
    info "  irm https://sendwire.dev/install.ps1 | iex"
    info "or:  winget install Sendwire.Sendwire"
    exit 0 ;;
  *) err "Unsupported OS: $os" ;;
esac
case "$arch" in
  x86_64|amd64) arch="x64" ;;
  arm64|aarch64) arch="arm64" ;;
  *) err "Unsupported architecture: $arch" ;;
esac
# An x64 shell under Rosetta on an Apple-silicon Mac wants the native arm64 build.
if [ "$os" = "darwin" ] && [ "$arch" = "x64" ] && \
   [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)" = "1" ]; then
  arch="arm64"
fi
platform="${os}-${arch}"

# --- resolve version + manifest ----------------------------------------------
# Manifest shape (produced by the release pipeline):
#   /latest                       -> "0.1.0"
#   /0.1.0/manifest.json          -> { "version": "...", "artifacts": {
#                                       "darwin-arm64": { "file": "...zip",      "sha256": "..." },
#                                       "linux-x64":    { "file": "...AppImage", "sha256": "..." } } }
version="${SENDWIRE_VERSION:-$(dl "${BASE_URL}/latest" | tr -d '[:space:]')}"
[ -n "$version" ] || err "Could not resolve the latest version from ${BASE_URL}/latest"
say "Installing Sendwire ${version} (${platform})"

manifest="$(dl "${BASE_URL}/${version}/manifest.json")" || err "No manifest for ${version}"

# Pull this platform's file + checksum out of the manifest (jq if present, else a
# small awk fallback so no dependency is required).
if command -v jq >/dev/null 2>&1; then
  file="$(printf '%s' "$manifest"   | jq -r --arg p "$platform" '.artifacts[$p].file   // empty')"
  sha="$(printf '%s' "$manifest"    | jq -r --arg p "$platform" '.artifacts[$p].sha256 // empty')"
else
  block="$(printf '%s' "$manifest" | tr -d '\n' | grep -o "\"${platform}\"[^}]*}")" || true
  file="$(printf '%s' "$block" | grep -o '"file"[^,}]*'   | head -1 | sed 's/.*: *"//; s/"//')"
  sha="$(printf '%s'  "$block" | grep -o '"sha256"[^,}]*' | head -1 | sed 's/.*: *"//; s/"//')"
fi
[ -n "$file" ] || err "No build for ${platform} in ${version}. See https://sendwire.dev/download"
[ -n "$sha" ]  || err "Manifest is missing a checksum for ${platform}."

# --- download + verify --------------------------------------------------------
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
info "Downloading ${file}…"
dlo "${BASE_URL}/${version}/${file}" "${tmp}/${file}"

info "Verifying checksum…"
if command -v shasum >/dev/null 2>&1; then
  got="$(shasum -a 256 "${tmp}/${file}" | awk '{print $1}')"
else
  got="$(sha256sum "${tmp}/${file}" | awk '{print $1}')"
fi
[ "$got" = "$sha" ] || err "Checksum mismatch — refusing to install. (expected ${sha}, got ${got})"

mkdir -p "$BIN_DIR"

# --- install ------------------------------------------------------------------
if [ "$os" = "darwin" ]; then
  dest="${SENDWIRE_INSTALL_DIR:-/Applications}"
  # Fall back to ~/Applications when /Applications is not writable (no sudo).
  if [ ! -w "$dest" ]; then dest="${HOME}/Applications"; mkdir -p "$dest"; fi

  info "Unpacking…"
  ( cd "$tmp" && unzip -q "$file" )
  app="$(/usr/bin/find "$tmp" -maxdepth 2 -name 'Sendwire.app' -print -quit)"
  [ -n "$app" ] || err "The download did not contain Sendwire.app."

  rm -rf "${dest}/Sendwire.app"
  mv "$app" "${dest}/Sendwire.app"

  # Downloaded + unsigned, so macOS quarantines it and Gatekeeper blocks launch.
  # Clearing the flag is the standard move for an unsigned open-source app until
  # signing + notarization land.
  xattr -dr com.apple.quarantine "${dest}/Sendwire.app" 2>/dev/null || true

  launcher="${dest}/Sendwire.app/Contents/Resources/bin/sendwire"
  for name in sendwire sw; do
    ln -sf "$launcher" "${BIN_DIR}/${name}"
  done
  installed="${dest}/Sendwire.app"

else # linux — an AppImage, extracted so it needs no libfuse2 at runtime
  dest="${SENDWIRE_INSTALL_DIR:-${HOME}/.local/share/sendwire}"
  rm -rf "${dest}/squashfs-root"
  mkdir -p "$dest"
  chmod +x "${tmp}/${file}"
  # Extract instead of running the AppImage in place. `--appimage-extract` is a
  # built-in AppImage feature that needs NO FUSE, so the app launches on distros
  # that ship libfuse3 (Ubuntu 22.04+) without the user hunting down libfuse2 —
  # by far the most common "the AppImage won't start" support ticket. The CLI
  # then points at the extracted AppRun rather than the self-mounting image.
  ( cd "$dest" && "${tmp}/${file}" --appimage-extract >/dev/null )
  rm -f "${tmp}/${file}"
  app="${dest}/squashfs-root"
  for name in sendwire sw; do
    ln -sf "${app}/AppRun" "${BIN_DIR}/${name}"
  done
  installed="$app"

  # Desktop integration: register Sendwire in the application menu with its icon,
  # so it's launchable from the GUI too, not just the CLI. Best-effort — a
  # headless box simply has no menu to add to, and every step is guarded.
  if [ -f "${app}/sendwire.desktop" ]; then
    apps="${HOME}/.local/share/applications"
    mkdir -p "$apps"
    # Rewrite the image-relative Exec/TryExec to the extracted AppRun's real path.
    sed -e "s|^Exec=.*|Exec=${app}/AppRun --no-sandbox %U|" \
        -e "s|^TryExec=.*|TryExec=${app}/AppRun|" \
        "${app}/sendwire.desktop" > "${apps}/sendwire.desktop"
    # Every icon size the AppImage ships, into the user's hicolor theme.
    for src in "${app}"/usr/share/icons/hicolor/*/apps/sendwire.png; do
      [ -f "$src" ] || continue
      size_dir="$(basename "$(dirname "$(dirname "$src")")")"
      icodir="${HOME}/.local/share/icons/hicolor/${size_dir}/apps"
      mkdir -p "$icodir" && cp -f "$src" "${icodir}/sendwire.png"
    done
    update-desktop-database "$apps" >/dev/null 2>&1 || true
  fi
fi

# --- PATH ---------------------------------------------------------------------
say "Installed → ${installed}"
info "CLI linked → ${BIN_DIR}/sw  (and ${BIN_DIR}/sendwire)"

case ":${PATH}:" in
  *":${BIN_DIR}:"*) launch_hint="Run:  sw" ;;
  *)
    # The user's LOGIN shell, not this script's — piping to bash would otherwise
    # always write .bashrc even for a zsh user.
    case "${SHELL:-}" in
      */zsh)  rc="${HOME}/.zshrc" ;;
      */bash) rc="${HOME}/.bashrc" ;;
      *)      rc="${HOME}/.profile" ;;
    esac
    printf '\nexport PATH="%s:$PATH"\n' "$BIN_DIR" >> "$rc"
    launch_hint="Added ${BIN_DIR} to PATH in ${rc}. Open a new terminal, then:  sw"
    ;;
esac

say "Done."
info "$launch_hint"

# Open it. A GUI install that prints text and then does nothing reads as broken —
# "did it work? where did it go?". So launch the app: it appears in the Dock, and
# it's now in Applications / Spotlight / Launchpad for every time after. Opt out
# with SENDWIRE_NO_LAUNCH=1 for scripted/headless installs.
if [ "$os" = "darwin" ]; then
  info "Also in Applications, Spotlight (⌘Space → Sendwire) and Launchpad."
  [ -z "${SENDWIRE_NO_LAUNCH:-}" ] && open "${installed}" 2>/dev/null || true
elif [ "$os" = "linux" ]; then
  info "Also in your application menu — search “Sendwire”."
  # Open it once so the install doesn't just print text and vanish. Backgrounded
  # and detached; on a headless box it simply finds no display and exits.
  [ -z "${SENDWIRE_NO_LAUNCH:-}" ] && ( "${app}/AppRun" >/dev/null 2>&1 & ) || true
fi
