#!/bin/bash
# Gegenbuch-Schleife: einrichten, dann in festem Takt beglaubigen.
set -uo pipefail

: "${INSTANZ:?INSTANZ fehlt (z. B. prod oder staging)}"
: "${CRM_URL:?CRM_URL fehlt – von welcher OpenCRM-Instanz soll geholt werden?}"
: "${CRM_EMAIL:?CRM_EMAIL fehlt – Dienstkonto im CRM mit dem Recht audit:read}"
: "${CRM_PASSWORD:?CRM_PASSWORD fehlt – Passwort dieses Dienstkontos}"

INTERVALL="${NOTARY_INTERVAL:-3600}"
BUCH=/gegenbuch/buch
SCHLUESSEL=/gegenbuch/schluessel
export NOTARY_STATE_FILE=/gegenbuch/beobachtungen.jsonl
export NOTARY_ALLOW_LOCAL=true          # Buch liegt auf dieser Maschine
export NOTARY_PUSH=false                # es gibt kein Ziel zum Pushen

# --- Rechte geraderuecken, dann Privilegien abgeben ------------------------
# Laeuft der Container als root, gehoert das Bind-Mount-Verzeichnis vermutlich
# ebenfalls root (typisch, wenn das Projekt als root geklont wurde). Wir setzen
# es auf den Arbeitsbenutzer um und starten uns selbst als dieser neu.
BENUTZER_UID="${PUID:-1000}"
BENUTZER_GID="${PGID:-1000}"
if [ "$(id -u)" = "0" ]; then
  if ! chown -R "$BENUTZER_UID:$BENUTZER_GID" /gegenbuch 2>/dev/null; then
    echo "[$INSTANZ] HINWEIS: Rechte auf /gegenbuch liessen sich nicht setzen." >&2
    echo "[$INSTANZ]   Falls es gleich an fehlenden Schreibrechten scheitert, auf dem Host:" >&2
    echo "[$INSTANZ]   chown -R $BENUTZER_UID:$BENUTZER_GID <datenverzeichnis>" >&2
  fi
  exec setpriv --reuid="$BENUTZER_UID" --regid="$BENUTZER_GID" --init-groups \
       --inh-caps=-all "$0" "$@"
fi

echo "[$INSTANZ] Gegenbuch startet – Quelle: $CRM_URL, Takt: ${INTERVALL}s"

# --- Signaturschlüssel: einmalig auf DIESER Maschine erzeugen ---------------
# Er verlässt den Rechner nie. OpenCRM kennt ihn nicht.
mkdir -p "$SCHLUESSEL"
if [ ! -f "$SCHLUESSEL/id_ed25519" ]; then
  echo "[$INSTANZ] Erzeuge Signaturschlüssel..."
  ssh-keygen -t ed25519 -f "$SCHLUESSEL/id_ed25519" -N "" -C "gegenbuch-$INSTANZ" -q
fi
chmod 600 "$SCHLUESSEL/id_ed25519"
if [ ! -f "$SCHLUESSEL/allowed_signers" ]; then
  echo "gegenbuch-$INSTANZ namespaces=\"git\" $(cat "$SCHLUESSEL/id_ed25519.pub")" \
    > "$SCHLUESSEL/allowed_signers"
fi

# --- Buch anlegen, falls noch nicht vorhanden ------------------------------
if [ ! -d "$BUCH/.git" ]; then
  echo "[$INSTANZ] Lege Gegenbuch an..."
  mkdir -p "$BUCH"
  git -C "$BUCH" init -q -b main
fi
cd "$BUCH" || exit 1

git config user.email "${NOTAR_EMAIL:-gegenbuch@localhost}"
git config user.name  "Gegenbuch $INSTANZ"
git config gpg.format ssh
git config user.signingkey "$SCHLUESSEL/id_ed25519.pub"
git config gpg.ssh.allowedSignersFile "$SCHLUESSEL/allowed_signers"

# Ein erster Commit, damit es eine Historie gibt, an die angehängt werden kann.
if ! git rev-parse HEAD >/dev/null 2>&1; then
  git commit -q -S --allow-empty -m "Gegenbuch $INSTANZ angelegt"
fi

# --- Schleife ---------------------------------------------------------------
# Jeder Rückgabecode außer 0 gehört angesehen. Der letzte Stand steht
# zusätzlich in status.txt, damit eine Überwachung ihn abgreifen kann, ohne
# Logs zu durchsuchen.
while true; do
  ZEIT=$(date -Iseconds)
  # Ausgabe mitschneiden, um den GRUND in die Statusdatei zu bekommen.
  #
  # Vorher stand dort nur das Etikett ("BEFUND"), und das ist fuer jeden
  # Exit-2 dasselbe - ein echter Widerspruch sieht darin aus wie eine
  # quittierpflichtige Erstsiegelung. Wer nur die Statusdatei liest, kann
  # nicht entscheiden, ob er handeln muss. Genau die Sorte Signal, gegen die
  # dieses Werkzeug gebaut ist.
  node /opt/notary/notary.mjs > /tmp/lauf.log 2>&1
  CODE=$?
  cat /tmp/lauf.log
  case $CODE in
    0) LAGE="in Ordnung" ;;
    1) LAGE="Betriebsfehler (Konfiguration, CRM nicht erreichbar, Commit)" ;;
    2) LAGE="BEFUND – Widerspruch zwischen CRM und Gegenbuch" ;;
    3) LAGE="nicht abschliessend feststellbar (u. a. erster Lauf)" ;;
    4) LAGE="Gedaechtnis fehlt – Bestaetigung noetig, siehe README" ;;
    5) LAGE="Anker unvollstaendig" ;;
    *) LAGE="unbekannter Code" ;;
  esac
  echo "[$INSTANZ] $ZEIT exit=$CODE ($LAGE)"
  # Die aussagekraeftigste Zeile mitnehmen, nicht einfach die erste.
  #
  # Bei Alarm ist das die ALARM-Zeile. Sonst die Zusammenfassung ("OK: …") -
  # denn ein Lauf kann davor beilaeufige Hinweise ausgeben (etwa das einmalige
  # Setzen einer Ueberwachungs-Grundlage), und die verdeckten sonst das
  # Ergebnis. Erst wenn beides fehlt, die erste Zeile ueberhaupt.
  GRUND=$(grep -m1 '^ALARM: ' /tmp/lauf.log | sed 's/^ALARM: //')
  [ -z "$GRUND" ] && GRUND=$(grep -m1 '^OK: ' /tmp/lauf.log)
  [ -z "$GRUND" ] && GRUND=$(grep -m1 -v '^[[:space:]]*$' /tmp/lauf.log)
  {
    printf '%s exit=%s %s\n' "$ZEIT" "$CODE" "$LAGE"
    [ -n "$GRUND" ] && printf 'Grund: %s\n' "$GRUND"
  } > /gegenbuch/status.txt
  sleep "$INTERVALL"
done
