#!/bin/sh
# ─────────────────────────────────────────────────────────────────────────────
#  The-Y CRM — Dateien (Anhänge, Belege, Rechnungs-PDFs, Aufnahmen …) aus einer Sicherung zurückspielen:
#  files-*.tar.gz → Volume minio-data. Läuft als Einmal-Dienst „restore-files“ (docker-compose.backup.yml, Profil restore).
#  Anleitung Schritt für Schritt: SELF-HOSTING.md → „Wiederherstellen“. Im Installationsordner:
#     docker compose stop app worker minio
#     docker compose run --rm restore-files files-YYYYMMDD-HHMMSS.tar.gz
#     docker compose start minio app worker
#  Optionen: --ja (ohne Rückfrage) · --ohne-sicherheitskopie (aktuellen Stand nicht vorher sichern)
#
#  1.1.52 (Review F14): vorher gab es für die Dateien weder Skript noch Anleitung. Jeder Fehler bricht ab, der alte Stand bleibt:
#   1. Archiv prüfen (gzip intakt, tar lesbar, Ablage-Ordner von MinIO enthalten).
#   2. Abbrechen, solange MinIO oder die App laufen (Dateien unter einem laufenden MinIO zu tauschen beschädigt dessen Ablage).
#   3. Sicherheitskopie des aktuellen Stands nach /backups/vor-wiederherstellung-files-<Zeit>.tar.gz.
#   4. Erst in einen Zwischenordner entpacken, dann austauschen; danach Dateizahl gegen das Archiv prüfen.
# ─────────────────────────────────────────────────────────────────────────────
set -eu -o pipefail
DIR="${BACKUP_DIR:-/backups}"
DATA="${MINIO_DATA_DIR:-/minio-data}"
TS=$(date -u +%Y%m%d-%H%M%S)
STAGE="$DATA/.they-restore-$TS"
OLD="$DATA/.they-old-$TS"
KOPIE="$DIR/vor-wiederherstellung-files-$TS.tar.gz"
log(){ echo "[restore-files $(date -u +%H:%M:%S)] $*"; }
fail(){ log "FEHLER: $*"; exit 1; }
trap 'rm -f "$KOPIE.part"' EXIT
usage(){
  echo "Nutzung: docker compose run --rm restore-files [--ja] [--ohne-sicherheitskopie] <files-YYYYMMDD-HHMMSS.tar.gz>"
  echo "Verfügbare Datei-Sicherungen in $DIR:"; ls -1 "$DIR"/files-*.tar.gz 2>/dev/null | sed 's#^.*/#  #' || echo "  (keine)"
}
# Antwortet ein Dienst überhaupt (auch mit Fehlerstatus)? → läuft.
reachable(){ out=$(wget -q -T 3 -O /dev/null "$1" 2>&1) && return 0; case "$out" in *"server returned error"*|*"HTTP/"*) return 0 ;; esac; return 1; }
# Oberste Einträge eines Ordners (auch versteckte), ohne . und ..
entries(){ for e in "$1"/* "$1"/.[!.]* "$1"/..?*; do [ -e "$e" ] || [ -L "$e" ] || continue; echo "$e"; done; }

JA=""; OHNE_KOPIE=""; F=""
for a in "$@"; do
  case "$a" in
    --ja|--yes) JA=1 ;;
    --ohne-sicherheitskopie) OHNE_KOPIE=1 ;;
    -h|--hilfe|--help) usage; exit 0 ;;
    -*) echo "Unbekannte Option: $a"; usage; exit 1 ;;
    *) [ -z "$F" ] || { echo "Bitte nur EINE Sicherungs-Datei angeben."; exit 1; }; F="$a" ;;
  esac
done
if [ -n "$F" ] && [ ! -f "$F" ] && [ -f "$DIR/$F" ]; then F="$DIR/$F"; fi
if [ -z "$F" ] || [ ! -f "$F" ]; then echo "Datei-Sicherung nicht gefunden: ${F:-<keine angegeben>}"; usage; exit 1; fi
[ -d "$DATA" ] || fail "Ablage-Ordner $DATA fehlt (Volume minio-data nicht eingebunden?)."
[ -w "$DATA" ] || fail "Ablage-Ordner $DATA ist schreibgeschützt — bitte über den Dienst restore-files starten (siehe oben)."

# 1) Archiv prüfen.
log "Prüfe $F …"
gunzip -t "$F" 2>/dev/null || fail "Archiv beschädigt (gzip-Prüfung fehlgeschlagen). Nichts geändert."
LIST=$(tar tzf "$F" 2>/dev/null) || fail "Archiv nicht lesbar (tar). Nichts geändert."
case "$LIST" in
  *".minio.sys/"*) ;;
  *) fail "Das Archiv ist keine Datei-Sicherung dieses CRM (Ablage-Ordner .minio.sys fehlt). Nichts geändert." ;;
esac
N_ARCH=$(printf '%s\n' "$LIST" | grep -cv '/$' || true)
log "Archiv in Ordnung: $N_ARCH Dateien."

# 2) MinIO und App müssen gestoppt sein.
if reachable "${MINIO_HEALTH_URL:-http://minio:9000/minio/health/live}"; then
  log "ABBRUCH: Der Datei-Speicher (MinIO) läuft noch."; echo "Zuerst:  docker compose stop app worker minio   — dann erneut starten. Nichts geändert."; exit 2
fi
if reachable "${APP_HEALTH_URL:-http://app:3000/api/public/health}"; then
  log "ABBRUCH: Die App läuft noch."; echo "Zuerst:  docker compose stop app worker minio   — dann erneut starten. Nichts geändert."; exit 2
fi

echo "!! ACHTUNG: Alle Dateien im Datei-Speicher werden durch den Stand dieser Sicherung ersetzt:"
echo "   $F"
if [ -z "$JA" ]; then
  if [ -t 0 ]; then
    printf 'Zum Fortfahren WIEDERHERSTELLEN eintippen (alles andere bricht ab): '
    read -r ANTWORT || ANTWORT=""
    [ "$ANTWORT" = "WIEDERHERSTELLEN" ] || { log "Abgebrochen — nichts geändert."; exit 1; }
  else
    fail "Ohne Terminal keine Rückfrage möglich — mit --ja bestätigen. Nichts geändert."
  fi
fi

# Reste eines abgebrochenen Laufs (nur unsere eigenen Zwischenordner) entfernen.
for e in "$DATA"/.they-restore-* "$DATA"/.they-old-*; do [ -e "$e" ] && rm -rf "$e"; done

# 3) Sicherheitskopie des aktuellen Stands.
if [ -z "$OHNE_KOPIE" ] && [ -n "$(entries "$DATA")" ]; then
  log "Sichere den aktuellen Stand …"
  if tar czf "$KOPIE.part" -C "$DATA" . 2>/dev/null && gunzip -t "$KOPIE.part" 2>/dev/null; then
    mv "$KOPIE.part" "$KOPIE"; log "Sicherheitskopie: $KOPIE"
  else
    fail "Sicherheitskopie des aktuellen Stands fehlgeschlagen (Platz auf $DIR?). Nichts geändert. Sonst mit --ohne-sicherheitskopie erneut starten."
  fi
fi

# 4) Entpacken in einen Zwischenordner (gleiches Volume → Austausch ohne Kopieren), dann austauschen.
mkdir -p "$STAGE"
if ! tar xzf "$F" -C "$STAGE" 2>/dev/null; then
  rm -rf "$STAGE"; fail "Entpacken fehlgeschlagen (Platz im Volume?). Nichts geändert."
fi
mkdir -p "$OLD"
rollback(){
  log "Austausch fehlgeschlagen — stelle den vorherigen Stand wieder her …"
  for e in $(entries "$DATA"); do case "$e" in "$STAGE"|"$OLD") ;; *) rm -rf "$e" ;; esac; done
  for e in $(entries "$OLD"); do mv "$e" "$DATA/" || true; done
  rm -rf "$OLD" "$STAGE"
  fail "Dateien NICHT zurückgespielt, der vorherige Stand ist wieder da."
}
IFS_ALT=$IFS; IFS='
'
for e in $(entries "$DATA"); do
  case "$e" in "$STAGE"|"$OLD") continue ;; esac
  mv "$e" "$OLD/" || rollback
done
for e in $(entries "$STAGE"); do mv "$e" "$DATA/" || rollback; done
IFS=$IFS_ALT
rm -rf "$OLD" "$STAGE"

N_NOW=$(find "$DATA" -type f -o -type l | wc -l | tr -d ' ')
[ "$N_NOW" = "$N_ARCH" ] || fail "Dateizahl passt nicht (Archiv $N_ARCH, jetzt $N_NOW) — bitte prüfen; vorheriger Stand: ${KOPIE:-keine Kopie}."
log "Dateien zurückgespielt und geprüft: $N_NOW Dateien."
[ -n "$OHNE_KOPIE" ] || [ ! -f "$KOPIE" ] || echo "Vorheriger Stand liegt in: $KOPIE (wird nicht automatisch gelöscht)."
echo "Jetzt im Installationsordner:  docker compose start minio app worker"
