#!/bin/sh
# Installs the Caprock desktop app on macOS:
#   curl -fsSL https://caprock.dev/mac.sh | sh
#
# It downloads the same universal .dmg the site's button links to, copies
# Caprock.app into /Applications (or ~/Applications when /Applications is not
# writable) and opens it. The app is signed with an Apple Developer ID and
# notarized by Apple; this is the terminal route to the same file.
# Run it again to update. Source: https://github.com/dspv/caprock
#
# CAPROCK_APP_DIR=<dir> installs somewhere else; CAPROCK_NO_OPEN=1 skips the
# open; NO_COLOR=1 prints plain lines.
#
# Everything lives in main(), called on the last line: when the script arrives
# through a pipe, sh has read all of it before the first command runs.
set -eu

REPO="https://github.com/dspv/caprock"
URL="$REPO/releases/latest/download/Caprock-macOS.dmg"

# ── Output: colour and a live bar on a terminal, plain lines otherwise ──────
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-dumb}" != "dumb" ]; then
  A=$(printf '\033[38;5;215m'); G=$(printf '\033[32m'); D=$(printf '\033[2m')
  B=$(printf '\033[1m'); R=$(printf '\033[0m'); TTY=1
else
  A=; G=; D=; B=; R=; TTY=
fi
step() { printf '  %s✓%s %-27s %s%s%s\n' "$G" "$R" "$1" "$D" "${2:-}" "$R"; }
fail() { [ -n "$TTY" ] && printf '\r\033[K'; printf '\n  %s✗ %s%s\n\n' "$B" "$1" "$R" >&2; exit 1; }
# mb BYTES -> "12.8"
mb() { t=$(( $1 * 10 / 1048576 )); printf '%d.%d' $((t / 10)) $((t % 10)); }
# bar HAVE TOTAL LABEL -> one frame of the progress line
bar() {
  pct=$(( $1 * 100 / $2 )); [ "$pct" -gt 100 ] && pct=100
  fill=$(( pct * 24 / 100 )); cells=""; i=0
  while [ "$i" -lt 24 ]; do
    if [ "$i" -lt "$fill" ]; then cells="${cells}█"; else cells="${cells} "; fi
    i=$((i + 1))
  done
  printf '\r  %s↓%s %-27s %s▕%s▏%s %3d%%  %s%s/%s MB%s\033[K' \
    "$A" "$R" "$3" "$A" "$cells" "$R" "$pct" "$D" "$(mb "$1")" "$(mb "$2")" "$R"
}

# download URL FILE LABEL: curl runs in the background and leaves its exit
# code in FILE.rc; on a terminal the bar is redrawn from the file's growth
# until that code appears. (Polling the pid would not do: a finished child
# stays a zombie until it is waited for, and kill -0 still succeeds on it.)
download() {
  head=$(curl -fsSLI "$1" 2>/dev/null) || head=
  total=$(printf '%s\n' "$head" | tr -d '\r' | awk 'tolower($1)=="content-length:"{n=$2} END{print n+0}')
  rc="$2.rc"; rm -f "$rc" "$rc.tmp"
  (
    trap 'kill "$c" 2>/dev/null; exit 1' TERM
    curl -fsSL -o "$2" "$1" 2> "$2.err" &
    c=$!
    if wait "$c"; then echo 0; else echo $?; fi > "$rc.tmp"
    mv "$rc.tmp" "$rc"
  ) &
  CURL_PID=$!
  while [ ! -f "$rc" ]; do
    if [ -n "$TTY" ]; then
      have=0; [ -f "$2" ] && have=$(wc -c < "$2" | tr -d ' ')
      if [ "${total:-0}" -gt 0 ]; then bar "${have:-0}" "$total" "$3"
      else printf '\r  %s↓%s %-27s %s%s MB%s\033[K' "$A" "$R" "$3" "$D" "$(mb "${have:-0}")" "$R"; fi
    fi
    sleep 0.15
  done
  wait "$CURL_PID" 2>/dev/null || true
  CURL_PID=
  [ -n "$TTY" ] && printf '\r\033[K'
  if [ "$(cat "$rc")" != 0 ]; then
    printf '  %s%s%s\n' "$D" "$(cat "$2.err")" "$R" >&2
    fail "The download failed. Check your connection and run the line again."
  fi
}

main() {
  START=$(date +%s)
  printf '\n  %s▲ caprock%s  %s— installing the desktop app%s\n\n' "$A$B" "$R" "$D" "$R"

  [ "$(uname -s)" = "Darwin" ] || fail "This installs the macOS app. Windows and Linux: https://caprock.dev/install/"
  OS=$(sw_vers -productVersion 2>/dev/null || echo "?")
  case "$(uname -m)" in arm64) CHIP="Apple Silicon" ;; *) CHIP="Intel" ;; esac
  step "Checked your Mac" "macOS $OS · $CHIP"

  VERSION=$(curl -fsSI "$REPO/releases/latest" 2>/dev/null | tr -d '\r' | awk 'tolower($1)=="location:"{n=split($2,p,"/v"); print p[n]}' | tail -1) || VERSION=
  LABEL="Downloading Caprock${VERSION:+ $VERSION}"

  DEST="${CAPROCK_APP_DIR:-/Applications}"
  if [ ! -w "$DEST" ]; then
    DEST="$HOME/Applications"
    mkdir -p "$DEST"
  fi

  tmp="$(mktemp -d)"
  CURL_PID=
  cleanup() {
    [ -n "${CURL_PID:-}" ] && kill "$CURL_PID" 2>/dev/null
    hdiutil detach -quiet "$tmp/mnt" 2>/dev/null || true
    rm -rf "$tmp"
  }
  trap cleanup EXIT
  trap 'exit 130' INT TERM

  download "$URL" "$tmp/Caprock.dmg" "$LABEL"
  step "Downloaded Caprock${VERSION:+ $VERSION}" "$(mb "$(wc -c < "$tmp/Caprock.dmg" | tr -d ' ')") MB"

  hdiutil attach -quiet -nobrowse -readonly -mountpoint "$tmp/mnt" "$tmp/Caprock.dmg" \
    || fail "Could not open the downloaded disk image."
  if [ -d "$DEST/Caprock.app" ]; then
    pkill -f "$DEST/Caprock.app/Contents/MacOS/" 2>/dev/null || true
    sleep 1
    rm -rf "$DEST/Caprock.app"
  fi
  ditto "$tmp/mnt/Caprock.app" "$DEST/Caprock.app"
  xattr -dr com.apple.quarantine "$DEST/Caprock.app" 2>/dev/null || true
  step "Installed" "$DEST/Caprock.app"

  if [ -z "${CAPROCK_NO_OPEN:-}" ]; then
    open "$DEST/Caprock.app"
    step "Opened Caprock"
  fi

  printf '\n  %sDone in %ss.%s %sRun this line again to update.%s\n\n' "$B" "$(( $(date +%s) - START ))" "$R" "$D" "$R"
}

main "$@" </dev/null
