#!/usr/bin/env bash
# install-bruno.sh — Install Bruno API client from the official APT repository.
# Hardened: arch-aware, signed-by keyring with retries (keyserver flake), idempotent,
# clean desktop entry, --dry-run.

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

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

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

Configures the official Bruno APT repository (signed-by keyring fetched from
keyserver.ubuntu.com with retries) and installs Bruno. Idempotent: safe to
re-run.

Options:
  --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 ;;
    -h|--help) usage; exit 0 ;;
    *) die "Unknown argument: $1 (try --help)" ;;
  esac
  shift
done

(( EUID == 0 )) || die "Must run as root. Try: sudo $SCRIPT_NAME"

[[ -r /etc/os-release ]] || die "/etc/os-release not found."
# shellcheck disable=SC1091
. /etc/os-release
case "${ID:-}:${ID_LIKE:-}" in
  *ubuntu*|*debian*) : ;;
  *) die "Unsupported distro: ${PRETTY_NAME:-unknown}." ;;
esac

ARCH="$(dpkg --print-architecture)"
[[ "$ARCH" == "amd64" ]] || die "Bruno APT repo only ships amd64 (detected: $ARCH)."
log "Detected: ${PRETTY_NAME:-unknown}, arch: $ARCH"

export DEBIAN_FRONTEND=noninteractive

KEYRING=/etc/apt/keyrings/bruno.gpg
SOURCES=/etc/apt/sources.list.d/bruno.list
KEY_ID="9FA6017ECABE0266"
DESKTOP=/usr/share/applications/bruno.desktop

log "Installing prerequisites..."
run "apt-get update -qq"
run "apt-get install -y curl gpg ca-certificates"

log "Configuring Bruno APT repository..."
run "install -d -m 0755 /etc/apt/keyrings"

if [[ ! -s "$KEYRING" ]]; then
  # keyserver.ubuntu.com is occasionally flaky — retry a few times.
  ok=0
  for attempt in 1 2 3 4 5; do
    if (( DRY_RUN )); then
      printf '  DRY-RUN: fetch key 0x%s (attempt %d)\n' "$KEY_ID" "$attempt"
      ok=1
      break
    fi
    if curl -fsSL --max-time 30 "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${KEY_ID}" \
        | gpg --dearmor -o "$KEYRING" 2>/dev/null && [[ -s "$KEYRING" ]]; then
      ok=1
      break
    fi
    warn "Key fetch failed (attempt $attempt/5); retrying in $((attempt*2))s..."
    sleep "$((attempt*2))"
  done
  (( ok )) || die "Could not retrieve Bruno signing key after 5 attempts."
  run "chmod 0644 '$KEYRING'"
fi

DESIRED_SRC="deb [arch=${ARCH} signed-by=${KEYRING}] http://debian.usebruno.com/ bruno stable"
if [[ ! -f "$SOURCES" ]] || ! grep -qxF "$DESIRED_SRC" "$SOURCES"; then
  run "printf '%s\n' '$DESIRED_SRC' > '$SOURCES'"
fi

log "Installing Bruno..."
run "apt-get update -qq"
run "apt-get install -y bruno"

log "Writing desktop entry..."
if (( DRY_RUN )); then
  printf '  DRY-RUN: write %s\n' "$DESKTOP"
else
  cat >"$DESKTOP" <<'EOF'
[Desktop Entry]
Name=Bruno
Comment=Open-source API Client
Exec=bruno %U
Terminal=false
Type=Application
Icon=bruno
Categories=Development;Utility;
StartupNotify=true
EOF
  chmod 0644 "$DESKTOP"
fi

log "Done. Bruno installed."
