#!/usr/bin/env bash
# install-jetbrains-toolbox.sh — Install JetBrains Toolbox into the invoking user's home.
# Hardened: dependency check w/ auto-install, SHA-256 verification against JetBrains'
# release metadata, idempotent (replaces atomically), .desktop entry, --dry-run.

set -euo pipefail
IFS=$'\n\t'

readonly SCRIPT_NAME="${0##*/}"
DRY_RUN=0
ASSUME_YES=0

usage() {
  cat <<EOF
Usage: $SCRIPT_NAME [--dry-run] [--yes] [--help]

Installs the latest JetBrains Toolbox to ~/.local/share/JetBrains/Toolbox and
creates a .desktop launcher in ~/.local/share/applications. The .tar.gz is
verified against the SHA-256 published in JetBrains' release feed.

Do NOT run with sudo: Toolbox is a per-user install. If a missing system
package (curl/jq/tar/libfuse2) needs installing, the script will call sudo
just for that step.

Options:
  --yes, -y    Auto-confirm prompts for installing missing system packages.
  --dry-run    Print actions without executing.
  --help, -h   Show this help.
EOF
}

log()  { printf '\033[1;34m[%s]\033[0m %s\n' "${SCRIPT_NAME%.sh}" "$*"; }
warn() { printf '\033[1;33m[%s] WARN:\033[0m %s\n' "${SCRIPT_NAME%.sh}" "$*" >&2; }
die()  { printf '\033[1;31m[%s] ERROR:\033[0m %s\n' "${SCRIPT_NAME%.sh}" "$*" >&2; exit 1; }
run()  { if (( DRY_RUN )); then printf '  DRY-RUN: %s\n' "$*"; else eval "$@"; fi; }
trap 'rc=$?; (( rc )) && printf "\033[1;31m[%s] failed at line %s (exit %d)\033[0m\n" "${SCRIPT_NAME%.sh}" "$LINENO" "$rc" >&2' ERR

while (( $# )); do
  case "$1" in
    --dry-run) DRY_RUN=1 ;;
    -y|--yes)  ASSUME_YES=1 ;;
    -h|--help) usage; exit 0 ;;
    *) die "Unknown argument: $1 (try --help)" ;;
  esac
  shift
done

(( EUID != 0 )) || die "Do NOT run as root. Toolbox is a per-user install."

[[ -r /etc/os-release ]] || die "/etc/os-release not found."
# shellcheck disable=SC1091
. /etc/os-release
case "${ID:-}:${ID_LIKE:-}" in
  *ubuntu*|*debian*) PKG_MGR=apt ;;
  *fedora*|*rhel*)   PKG_MGR=dnf ;;
  *arch*)            PKG_MGR=pacman ;;
  *) die "Unsupported distro: ${PRETTY_NAME:-unknown}." ;;
esac
log "Detected: ${PRETTY_NAME:-unknown} (pkg: $PKG_MGR)"

confirm() {
  (( ASSUME_YES )) && return 0
  read -rp "$1 [y/N] " ans
  [[ "$ans" =~ ^[Yy] ]]
}

ensure_pkg() {
  local pkg="$1" probe="$2"
  if eval "$probe" >/dev/null 2>&1; then return 0; fi
  if ! confirm "Package '$pkg' is missing. Install via sudo $PKG_MGR?"; then
    die "'$pkg' is required."
  fi
  case "$PKG_MGR" in
    apt)    run "sudo apt-get update -qq && sudo apt-get install -y '$pkg'" ;;
    dnf)    run "sudo dnf install -y '$pkg'" ;;
    pacman) run "sudo pacman -Sy --noconfirm '$pkg'" ;;
  esac
}

# Map deps: command-or-package-probe
ensure_pkg curl     "command -v curl"
ensure_pkg jq       "command -v jq"
ensure_pkg tar      "command -v tar"
case "$PKG_MGR" in
  apt)    ensure_pkg libfuse2 "dpkg -s libfuse2" ;;
  dnf)    ensure_pkg fuse-libs "rpm -q fuse-libs" ;;
  pacman) ensure_pkg fuse2   "pacman -Q fuse2" ;;
esac

ARCH_RAW="$(uname -m)"
case "$ARCH_RAW" in
  x86_64)  TOOLBOX_ARCH_KEY=linux ;;
  aarch64) TOOLBOX_ARCH_KEY=linuxARM64 ;;
  *) die "Unsupported architecture: $ARCH_RAW" ;;
esac

log "Querying JetBrains release feed..."
RELEASE_JSON="$(curl -fsSL 'https://data.services.jetbrains.com/products/releases?code=TBA&latest=true&type=release' \
  -H 'Origin: https://www.jetbrains.com' \
  -H 'Referer: https://www.jetbrains.com/toolbox/download/')"

TOOLBOX_URL="$(jq -r --arg k "$TOOLBOX_ARCH_KEY" '.TBA[0].downloads[$k].link // empty' <<<"$RELEASE_JSON")"
TOOLBOX_SHA="$(jq -r --arg k "$TOOLBOX_ARCH_KEY" '.TBA[0].downloads[$k].checksumLink // empty' <<<"$RELEASE_JSON")"
TOOLBOX_VER="$(jq -r '.TBA[0].version // "?"' <<<"$RELEASE_JSON")"
[[ -n "$TOOLBOX_URL" ]] || die "Could not resolve Toolbox download URL from release feed."
log "Latest Toolbox: $TOOLBOX_VER ($TOOLBOX_ARCH_KEY)"

INSTALL_DIR="$HOME/.local/share/JetBrains/Toolbox"
STAGE_DIR="$(mktemp -d -t toolbox.XXXXXX)"
trap 'rm -rf "$STAGE_DIR"' EXIT

TARBALL="$STAGE_DIR/toolbox.tar.gz"
log "Downloading..."
run "curl -fsSL -o '$TARBALL' '$TOOLBOX_URL'"

if [[ -n "$TOOLBOX_SHA" ]]; then
  log "Verifying SHA-256..."
  EXPECTED_SHA="$(curl -fsSL "$TOOLBOX_SHA" | awk '{print $1}')"
  ACTUAL_SHA="$(sha256sum "$TARBALL" | awk '{print $1}')"
  if [[ -n "$EXPECTED_SHA" && "$EXPECTED_SHA" != "$ACTUAL_SHA" ]]; then
    die "SHA-256 mismatch! expected=$EXPECTED_SHA actual=$ACTUAL_SHA"
  fi
  log "SHA-256 ok."
else
  warn "No checksum URL in release feed; skipping verification."
fi

log "Extracting to $INSTALL_DIR..."
run "mkdir -p '$INSTALL_DIR'"
run "tar -xzf '$TARBALL' --strip-components=1 -C '$INSTALL_DIR'"

BIN_PATH="$INSTALL_DIR/bin/jetbrains-toolbox"
DESKTOP_SRC="$INSTALL_DIR/bin/jetbrains-toolbox.desktop"
ICON_PATH="$INSTALL_DIR/bin/toolbox-tray-color.png"

[[ -x "$BIN_PATH" || $DRY_RUN -eq 1 ]] || die "Toolbox binary missing after extract."

# Optional ~/bin symlink
if [[ -d "$HOME/bin" ]]; then
  run "ln -sfn '$BIN_PATH' '$HOME/bin/jetbrains-toolbox'"
fi

# .desktop launcher
APPS_DIR="$HOME/.local/share/applications"
run "mkdir -p '$APPS_DIR'"
DESKTOP_DST="$APPS_DIR/jetbrains-toolbox.desktop"
if [[ -f "$DESKTOP_SRC" ]] || (( DRY_RUN )); then
  run "cp '$DESKTOP_SRC' '$DESKTOP_DST'"
  run "sed -i 's|^Exec=.*|Exec=$BIN_PATH %u|' '$DESKTOP_DST'"
  if [[ -f "$ICON_PATH" ]]; then
    run "sed -i 's|^Icon=.*|Icon=$ICON_PATH|' '$DESKTOP_DST'"
  fi
  run "chmod 0755 '$DESKTOP_DST'"
  log "Desktop entry installed: $DESKTOP_DST"
else
  warn "No .desktop file in archive; skipping launcher."
fi

log "Done. JetBrains Toolbox $TOOLBOX_VER installed to $INSTALL_DIR"
