#!/usr/bin/env bash
# Clusev updater — pull the latest code and re-run the idempotent installer (root required).
# One command to update an existing install:
#
#   sudo ./update.sh
#
# In order:
#   1. Mark the repo a safe git dir for root. install.sh chowns the tree to the `clusev` user,
#      so a root-run `git pull` would otherwise refuse with "dubious ownership".
#   2. git pull --ff-only on the tracked branch. Aborts cleanly on any conflict / divergence —
#      it NEVER discards local changes.
#   3. Self-update: if update.sh itself changed in the pull, re-exec the NEW copy once (guarded
#      against loops) so improvements to this very script take effect on the same run.
#   4. Hand off to ./install.sh — idempotent: rebuilds the image, restarts the stack, migrates,
#      refreshes the MOTD and fixes ownership. Run NON-interactively (stdin from /dev/null) so
#      it never re-prompts; secrets and the configured domain / ACME e-mail are preserved.
set -euo pipefail

cd "$(dirname "$0")"
REPO_DIR="$(pwd)"

# set_stage: publish a coarse update stage for the in-browser progress screen (best-effort — the
# app container serves run/update-phase.json to it). A write failure must never fail the update.
# Written first as "fetch" so the screen leaves the time-guess behind the moment the pull begins,
# and so a stale stage from a previous update is reset.
set_stage() {
  mkdir -p "$REPO_DIR/run" 2>/dev/null || true
  printf '{"stage":"%s","at":%s}\n' "$1" "$(date +%s 2>/dev/null || echo 0)" > "$REPO_DIR/run/update-phase.json" 2>/dev/null || true
  chmod 644 "$REPO_DIR/run/update-phase.json" 2>/dev/null || true
  return 0
}
set_stage fetch

bold() { printf '\033[1m%s\033[0m\n' "$*"; }
info() { printf '  %s\n' "$*"; }
die()  { printf '\033[31m  x %s\033[0m\n' "$*" >&2; exit 1; }

[ "$(id -u)" = 0 ] || die "Bitte mit sudo ausfuehren: sudo ./update.sh"
[ -f docker-compose.prod.yml ] || die "Keine Clusev-Installation hier (docker-compose.prod.yml fehlt)."
[ -x ./install.sh ] || [ -f ./install.sh ] || die "install.sh fehlt — Repo unvollstaendig."
command -v git >/dev/null 2>&1 || die "git ist nicht installiert."

bold "Clusev Update"
echo  "============="

# Steps 1–3 run only on the first pass; a re-exec (after a self-update) jumps straight to step 4.
if [ "${CLUSEV_UPDATE_REEXEC:-0}" != 1 ]; then
  # 1. let root operate on the clusev-owned working tree
  git config --global --add safe.directory "$REPO_DIR" 2>/dev/null || true

  # 2. fast-forward pull only — never auto-merge or throw away local edits
  before_hash="$(sha256sum -- "$0" | cut -d' ' -f1)"
  info "Hole Aktualisierungen (git pull --ff-only) ..."
  git pull --ff-only \
    || die "git pull fehlgeschlagen (lokale Aenderungen oder divergierter Branch). Mit 'git status' pruefen und erneut versuchen."
  after_hash="$(sha256sum -- "$0" | cut -d' ' -f1)"

  # 3. self-update: relaunch the new update.sh if it changed
  if [ "$before_hash" != "$after_hash" ]; then
    info "update.sh wurde aktualisiert — starte die neue Version ..."
    exec env CLUSEV_UPDATE_REEXEC=1 "$0" "$@"
  fi
fi

# 4. apply via the idempotent installer, non-interactively (no prompts; config preserved)
info "Wende Update an (install.sh) ..."
exec ./install.sh </dev/null
