#!/usr/bin/env bash
# Vaultwarden Updater (backend + web-vault) for Proxmox LXC
# - Selectively updates only what's outdated
# - Run as root. Usage:
#     ./vw-build-update.sh          # update if needed
#     ./vw-build-update.sh --check  # just report, no changes
# bash -c "$(wget -qLO - https://files.esser.space/iso/etc/vw/vw-build-update.sh)"

#set -euo pipefail
#
#echo "== Preflight =="
#cat /etc/debian_version || true
#lsb_release -a 2>/dev/null || true
#
#echo "== Backup hint (do on PVE host): pct snapshot <CTID> pre-bookworm =="
#echo
#
#echo "== Ensure old system is fully updated (Bullseye) =="
#apt-get update
#apt-get -y full-upgrade
#apt-get -y autoremove --purge
#
#echo "== Switch APT sources to Debian 12 (bookworm) =="
## sources.list
#sed -i 's/bullseye/bookworm/g' /etc/apt/sources.list
#
## sources.list.d
#if ls /etc/apt/sources.list.d/*.list >/dev/null 2>&1; then
#  sed -i 's/bullseye/bookworm/g' /etc/apt/sources.list.d/*.list || true
#fi
#
#echo "== If you use Debian security lines, ensure they exist =="
## (Optional) Add standard bookworm security if missing:
#grep -q "security.debian.org" /etc/apt/sources.list || cat >> /etc/apt/sources.list <<'EOF'
#
#deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
#EOF
#
#echo "== Update package lists (Bookworm) =="
#apt-get update
#
#echo "== Upgrade base system first (minimal) =="
#apt-get -y upgrade
#
#echo "== Full distro upgrade =="
## Bookworm introduces non-free-firmware; we include it above already.
#apt-get -y full-upgrade
#
#echo "== Cleanup =="
#apt-get -y autoremove --purge
#apt-get -y autoclean
#
#echo "== Confirm OpenSSL =="
#openssl version -a || true
#ldconfig -p | grep -E 'libssl\.so|libcrypto\.so' || true
#
#echo "== Done. Restart the container from PVE host: pct restart <CTID> =="

set -Eeuo pipefail
MODE="${1:-update}"   # default: update, or "--check"

say() { printf "%s\n" "$*"; }
die() { printf "[-] %s\n" "$*" >&2; exit 1; }

say "[*] Detecting service …"
SVC="$(systemctl list-units --type=service --no-legend | awk '/vaultwarden|bitwarden_rs/ {print $1; exit}')"
[[ -z "$SVC" ]] && die "No vaultwarden/bitwarden_rs systemd service found."

UNIT="$(systemctl show -p FragmentPath --value "$SVC")"
[[ -z "$UNIT" || ! -f "$UNIT" ]] && UNIT="/etc/systemd/system/$SVC"

VW_DIR="$(grep -iE '^WorkingDirectory=' "$UNIT" 2>/dev/null | head -n1 | cut -d= -f2 || true)"
[[ -z "${VW_DIR:-}" ]] && VW_DIR="/opt/vaultwarden"

BIN_PATH="$(grep -iE '^ExecStart=' "$UNIT" | sed -E 's/^ExecStart=//; s/^[^ ]* //; s/[[:space:]].*$//' | head -n1 || true)"
[[ -z "${BIN_PATH:-}" ]] && BIN_PATH="$(command -v vaultwarden || true)"
[[ -z "${BIN_PATH:-}" && -x "$VW_DIR/bin/vaultwarden" ]] && BIN_PATH="$VW_DIR/bin/vaultwarden"
[[ -z "${BIN_PATH:-}" ]] && die "Could not determine vaultwarden binary path."

say "[*] Service: $SVC"
say "[*] Vaultwarden dir: $VW_DIR"
say "[*] Binary: $BIN_PATH"

changed_backend=0
changed_web=0

get_latest_vw_tag() {
  curl -fsSL https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest |
    grep -m1 '"tag_name"' | cut -d\" -f4
}
get_latest_web_tag() {
  curl -fsSL https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest |
    grep -m1 '"tag_name"' | cut -d\" -f4
}

detect_current_backend_ver() {
  [[ -x "$BIN_PATH" ]] && "$BIN_PATH" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true
}
detect_current_web_ver() {
  [[ -f "$VW_DIR/web-vault/.vw_web_version" ]] && cat "$VW_DIR/web-vault/.vw_web_version" || echo ""
}

say "[*] Checking current versions …"
CUR_BACKEND="$(detect_current_backend_ver || true)"
CUR_WEB="$(detect_current_web_ver || true)"
say "    - Backend (installed): ${CUR_BACKEND:-unknown}"
say "    - Web     (installed): ${CUR_WEB:-unknown}"

say "[*] Fetching latest release info …"
VW_TAG="$(get_latest_vw_tag)"; [[ -z "$VW_TAG" ]] && die "Could not get latest Vaultwarden tag."
WV_TAG="$(get_latest_web_tag)"; [[ -z "$WV_TAG" ]] && die "Could not get latest Web-Vault tag."
say "    - Backend (latest): $VW_TAG"
say "    - Web     (latest): $WV_TAG"

if [[ "$MODE" == "--check" ]]; then
  [[ "$CUR_BACKEND" == "${VW_TAG#v}" || "$CUR_BACKEND" == "$VW_TAG" ]] \
    && say "[=] Backend up-to-date." || say "[!] Backend update available."
  [[ -n "$CUR_WEB" && "$CUR_WEB" == "$WV_TAG" ]] \
    && say "[=] Web-vault up-to-date." || say "[!] Web-vault update available."
  exit 0
fi

need_backend_update=1
[[ "$CUR_BACKEND" == "${VW_TAG#v}" || "$CUR_BACKEND" == "$VW_TAG" ]] && need_backend_update=0
need_web_update=1
[[ -n "$CUR_WEB" && "$CUR_WEB" == "$WV_TAG" ]] && need_web_update=0

if (( need_backend_update==0 && need_web_update==0 )); then
  say "[=] Everything already up-to-date. No changes."
  exit 0
fi

export DEBIAN_FRONTEND=noninteractive
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
TS="$(date +%F_%H%M%S)"
mkdir -p /root/vw-backup

say "[*] Stopping service …"
systemctl stop "$SVC" || true

# --- Backend update ---
if (( need_backend_update==1 )); then
  say "[*] Backend: installing build deps …"
  apt-get update -qq
  apt-get install -y -qq --no-install-recommends \
    build-essential pkg-config ca-certificates curl git \
    libssl-dev zlib1g-dev libsqlite3-dev libpq-dev libmariadb-dev-compat

  say "[*] Ensure Rust toolchain …"
  if ! command -v cargo >/dev/null 2>&1; then
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
    export PATH="$HOME/.cargo/bin:$PATH"
  else
    rustup -q self update || true
  fi
  export PATH="$HOME/.cargo/bin:$PATH"

  say "[*] Cloning vaultwarden ${VW_TAG} …"
  git clone --depth 1 --branch "$VW_TAG" https://github.com/dani-garcia/vaultwarden.git "$TMP/vaultwarden"

  say "[*] Building backend …"
  pushd "$TMP/vaultwarden" >/dev/null
  cargo build --release --features "sqlite,mysql,postgresql"
  popd >/dev/null

  NEW_BIN="$TMP/vaultwarden/target/release/vaultwarden"
  [[ -x "$NEW_BIN" ]] || die "Build failed (vaultwarden missing)."

  say "[*] Backup & install backend binary …"
  [[ -f "$BIN_PATH" ]] && cp -a "$BIN_PATH" "/root/vw-backup/vaultwarden_${TS}"
  install -D -m0755 "$NEW_BIN" "$BIN_PATH"
  changed_backend=1
else
  say "[=] Backend already current. Skipping."
fi

# --- Web-vault update ---
if (( need_web_update==1 )); then
  say "[*] Downloading web-vault ${WV_TAG} …"
  curl -fL -o "$TMP/webvault.tar.gz" \
    "https://github.com/dani-garcia/bw_web_builds/releases/download/${WV_TAG}/bw_web_${WV_TAG}.tar.gz"

  say "[*] Backup current web-vault …"
  [[ -d "$VW_DIR/web-vault" ]] && \
    tar -C "$VW_DIR" -czf "/root/vw-backup/webvault_${TS}.tgz" web-vault || true

  say "[*] Installing new web-vault …"
  rm -rf "$VW_DIR/web-vault"
  mkdir -p "$VW_DIR/web-vault"
  
  TMP_WEB="$TMP/web-extract"
  mkdir -p "$TMP_WEB"
  tar -xzf "$TMP/webvault.tar.gz" -C "$TMP_WEB"
  
  IDX="$(find "$TMP_WEB" -maxdepth 6 -type f -name index.html | head -n1)"
  [[ -n "$IDX" ]] || die "index.html not found in web-vault archive"
  
  SRC_DIR="$(dirname "$IDX")"
  cp -a "$SRC_DIR/." "$VW_DIR/web-vault/"
  
  [[ -f "$VW_DIR/web-vault/index.html" ]] || die "web-vault install failed (index.html missing)"
  
  echo "$WV_TAG" > "$VW_DIR/web-vault/.vw_web_version"

  # ensure .env points correctly
  if [[ -f "$VW_DIR/.env" ]]; then
    if ! grep -q '^WEB_VAULT_FOLDER=' "$VW_DIR/.env"; then
      echo "WEB_VAULT_FOLDER=$VW_DIR/web-vault" >> "$VW_DIR/.env"
    else
      sed -i "s#^WEB_VAULT_FOLDER=.*#WEB_VAULT_FOLDER=$VW_DIR/web-vault#g" "$VW_DIR/.env"
    fi
  fi
  changed_web=1
else
  say "[=] Web-vault already current. Skipping."
fi

OWNER="$(stat -c '%U:%G' "$VW_DIR" 2>/dev/null || echo root:root)"
chown -R "$OWNER" "$BIN_PATH" "$VW_DIR/web-vault" 2>/dev/null || true

if (( changed_backend==1 || changed_web==1 )); then
  say "[*] Starting service …"
  systemctl daemon-reload
  systemctl start "$SVC"
  sleep 2
  systemctl --no-pager --full status "$SVC" || true
  say "[+] Done. Backups in /root/vw-backup"
else
  say "[=] No changes applied."
fi


