#!/bin/sh
# PUBLISHED COPY — source of truth: apps/desktop/packaging/install.sh
# Darvin's Selection user-local installer; set DARVIN_SHOT_REPOSITORY if its repository differs.

set -eu

REPOSITORY="${DARVIN_SHOT_REPOSITORY:-cagrimertbakirci/darvin-shot}"
APP_NAME='Darvin'\''s Selection'
BIN_NAME='darvin-shot'
PREFIX="${HOME}/.local"
BIN_DIR="${PREFIX}/bin"
DATA_DIR="${PREFIX}/share"
DESKTOP_FILE="${DATA_DIR}/applications/darvin-shot.desktop"
ICON_FILE="${DATA_DIR}/icons/hicolor/128x128/apps/darvin-shot.png"

say() {
  printf '%s\n' "$*"
}

die() {
  say "error: $*" >&2
  exit 1
}

need_downloader() {
  if command -v curl >/dev/null 2>&1; then
    DOWNLOADER='curl'
  elif command -v wget >/dev/null 2>&1; then
    DOWNLOADER='wget'
  else
    die 'install curl or wget, then run this installer again'
  fi
}

fetch() {
  url=$1
  destination=$2
  case "$DOWNLOADER" in
    curl) curl -fsSL --retry 3 -o "$destination" "$url" ;;
    wget) wget -qO "$destination" "$url" ;;
  esac
}

sha256() {
  file=$1
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$file" | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$file" | awk '{print $1}'
  else
    die 'install sha256sum or shasum to verify the download'
  fi
}

uninstall() {
  case "$OS" in
    linux)
      rm -f "${BIN_DIR}/${BIN_NAME}" "$DESKTOP_FILE" "$ICON_FILE"
      say "Removed ${APP_NAME} from ${PREFIX}."
      ;;
    macos)
      say "The macOS installer only opens a DMG; move ${APP_NAME}.app to Trash to uninstall it."
      ;;
    windows)
      say "Uninstall ${APP_NAME} from Windows Settings > Apps."
      ;;
  esac
}

case "$(uname -s)" in
  Linux) OS='linux' ;;
  Darwin) OS='macos' ;;
  MINGW*|MSYS*|CYGWIN*) OS='windows' ;;
  *) die "unsupported operating system: $(uname -s)" ;;
esac

case "$(uname -m)" in
  x86_64|amd64) ARCH='x86_64' ;;
  aarch64|arm64) ARCH='aarch64' ;;
  *) die "unsupported CPU architecture: $(uname -m)" ;;
esac

if [ "${1:-}" = '--uninstall' ]; then
  uninstall
  exit 0
fi
if [ "${1:-}" != '' ]; then
  die "unknown option: $1 (use --uninstall)"
fi

case "$REPOSITORY" in
  REPO_URL|*'/'|'/'*) die 'release repository is not configured; set DARVIN_SHOT_REPOSITORY=OWNER/REPOSITORY' ;;
esac

need_downloader
TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/darvin-shot.XXXXXX")
trap 'rm -rf "$TMP_DIR"' 0 HUP INT TERM

API_JSON="${TMP_DIR}/releases.json"
fetch "https://api.github.com/repos/${REPOSITORY}/releases?per_page=100" "$API_JSON" \
  || die 'could not query GitHub releases'

# GitHub returns releases newest-first. Keep the first complete release object
# whose tag begins desktop-v, so unrelated web releases are ignored.
RELEASE_START=$(grep -n '"tag_name": "desktop-v' "$API_JSON" | sed -n '1{s/:.*//;p;}')
[ -n "$RELEASE_START" ] || die 'no published release tagged desktop-v* was found'
RELEASE_JSON="${TMP_DIR}/release.json"
awk -v start="$RELEASE_START" '
  NR >= start {
    if (NR > start && $0 ~ /^  }[,]?$/) exit
    print
  }
' "$API_JSON" > "$RELEASE_JSON"

TAG=$(sed -n 's/^[[:space:]]*"tag_name": "\([^"]*\)".*/\1/p' "$RELEASE_JSON" | sed -n '1p')
[ -n "$TAG" ] || die 'could not read the desktop release tag'
ASSET_URLS=$(sed -n 's/^[[:space:]]*"browser_download_url": "\([^"]*\)".*/\1/p' "$RELEASE_JSON")
[ -n "$ASSET_URLS" ] || die "release ${TAG} does not contain downloadable assets"

select_asset() {
  while IFS= read -r url; do
    case "${OS}:${ARCH}:${url}" in
      linux:x86_64:*amd64*.AppImage|linux:x86_64:*x86_64*.AppImage) printf '%s\n' "$url"; return 0 ;;
      linux:aarch64:*aarch64*.AppImage|linux:aarch64:*arm64*.AppImage) printf '%s\n' "$url"; return 0 ;;
      linux:x86_64:*linux*x86_64*.tar.gz|linux:x86_64:*linux*amd64*.tar.gz) printf '%s\n' "$url"; return 0 ;;
      linux:aarch64:*linux*aarch64*.tar.gz|linux:aarch64:*linux*arm64*.tar.gz) printf '%s\n' "$url"; return 0 ;;
      macos:aarch64:*aarch64*.dmg|macos:aarch64:*arm64*.dmg) printf '%s\n' "$url"; return 0 ;;
      macos:x86_64:*x64*.dmg|macos:x86_64:*x86_64*.dmg) printf '%s\n' "$url"; return 0 ;;
      windows:x86_64:*x64-setup.exe|windows:x86_64:*x86_64-setup.exe) printf '%s\n' "$url"; return 0 ;;
      windows:x86_64:*windows-x86_64*.zip|windows:x86_64:*win64*.zip) printf '%s\n' "$url"; return 0 ;;
    esac
  done
  return 1
}

ASSET_URL=$(printf '%s\n' "$ASSET_URLS" | select_asset) \
  || die "release ${TAG} has no ${OS}/${ARCH} installer"
CHECKSUM_URL=$(printf '%s\n' "$ASSET_URLS" | sed -n '/\/checksums\.txt$/p' | sed -n '1p')
[ -n "$CHECKSUM_URL" ] || die "release ${TAG} has no checksums.txt"

# Verify against the exact basename of the selected asset.
ASSET_BASENAME=${ASSET_URL##*/}

if [ "$OS" = 'windows' ]; then
  say "${APP_NAME} for Windows: ${ASSET_URL}"
  say 'Download the installer, then run it from Explorer.'
  exit 0
fi

CHECKSUM_FILE="${TMP_DIR}/checksums.txt"
ARCHIVE="${TMP_DIR}/download"
fetch "$CHECKSUM_URL" "$CHECKSUM_FILE" || die 'could not download checksums.txt'
EXPECTED_SHA=$(awk -v name="$ASSET_BASENAME" '$NF == name { print $1; exit }' "$CHECKSUM_FILE")
[ -n "$EXPECTED_SHA" ] || die "checksums.txt has no checksum for ${ASSET_BASENAME}"

say "Downloading ${APP_NAME} ${TAG}..."
fetch "$ASSET_URL" "$ARCHIVE" || die 'download failed'
ACTUAL_SHA=$(sha256 "$ARCHIVE")
[ "$ACTUAL_SHA" = "$EXPECTED_SHA" ] \
  || die "checksum mismatch (expected ${EXPECTED_SHA}, got ${ACTUAL_SHA})"
say 'Checksum verified.'

if [ "$OS" = 'macos' ]; then
  DOWNLOADS_DIR="${HOME}/Downloads"
  mkdir -p "$DOWNLOADS_DIR"
  DMG_PATH="${DOWNLOADS_DIR}/${APP_NAME}-${TAG}.dmg"
  mv "$ARCHIVE" "$DMG_PATH"
  trap - 0 HUP INT TERM
  rm -rf "$TMP_DIR"
  say "Opening ${DMG_PATH}. Drag ${APP_NAME}.app into Applications to install it."
  if command -v open >/dev/null 2>&1; then
    open "$DMG_PATH"
  else
    say "Open ${DMG_PATH} manually."
  fi
  exit 0
fi

mkdir -p "$BIN_DIR" "$(dirname "$DESKTOP_FILE")" "$(dirname "$ICON_FILE")"
case "$ASSET_BASENAME" in
  *.tar.gz)
    tar -xzf "$ARCHIVE" -C "$TMP_DIR" || die 'could not extract the release tarball'
    EXTRACTED=$(find "$TMP_DIR" -type f -name "$BIN_NAME" | sed -n '1p')
    [ -n "$EXTRACTED" ] || die "tarball does not contain ${BIN_NAME}"
    mv "$EXTRACTED" "${BIN_DIR}/${BIN_NAME}"
    ;;
  *)
    mv "$ARCHIVE" "${BIN_DIR}/${BIN_NAME}"
    ;;
esac
chmod 755 "${BIN_DIR}/${BIN_NAME}"

# Icon is a display asset only; executable bytes always come from the
# checksum-verified release artifact above. Prefer the icon bundled in the
# tarball; fall back to a best-effort fetch, and never fail the install on it.
BUNDLED_ICON=$(find "$TMP_DIR" -type f -name "${BIN_NAME}.png" 2>/dev/null | sed -n '1p')
if [ -n "$BUNDLED_ICON" ]; then
  mv "$BUNDLED_ICON" "$ICON_FILE"
else
  fetch "https://raw.githubusercontent.com/${REPOSITORY}/main/darvin-shot.png" "$ICON_FILE" \
    || say 'note: could not fetch the desktop icon (the app still works).'
fi
cat > "$DESKTOP_FILE" <<EOF
[Desktop Entry]
Type=Application
Name=Darvin's Selection
Comment=Fast screenshots and dar.vin links
Exec=${BIN_DIR}/${BIN_NAME}
Icon=darvin-shot
Terminal=false
Categories=Graphics;Utility;
Keywords=screenshot;capture;darvin;
StartupWMClass=vin.dar.shot
EOF

say "Installed ${APP_NAME} to ${BIN_DIR}/${BIN_NAME}."
case ":${PATH}:" in
  *":${BIN_DIR}:"*) ;;
  *) say "Add ${BIN_DIR} to PATH to run '${BIN_NAME}' from a terminal." ;;
esac
say 'Re-run this installer later to upgrade, or pass --uninstall to remove it.'
