#!/usr/bin/env bash
#
# OPENBUREAU — All-in-One LXC für Proxmox VE (Supabase-Kern + CMS).
#
# AUSFÜHREN AUF DEM PROXMOX-HOST (nicht im Container), als root:
#   bash create-openbureau-lxc.sh
#
# Legt einen unprivileged Debian-12-LXC an (Docker-fähig: nesting + keyctl),
# installiert Docker, zieht das Repo, generiert alle Secrets (POSTGRES_PASSWORD,
# JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY) und befüllt die .env. Optional baut
# und startet es den Stack direkt.

set -euo pipefail

############################  CONFIG  ############################
# Alle Werte sind per Umgebungsvariable überschreibbar, z.B.:
#   ROOTFS_STORAGE=local-zfs HOSTNAME=openbureau-dev SITE_DOMAIN=dev.openbureau.ch \
#   IP=192.168.1.134/24 GATEWAY=192.168.1.1 bash create-openbureau-lxc.sh
CTID="${CTID:-$(pvesh get /cluster/nextid)}"
HOSTNAME="${HOSTNAME:-openbureau}"

# Storage
TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}"
ROOTFS_STORAGE="${ROOTFS_STORAGE:-local-lvm}"
DISK_GB="${DISK_GB:-20}"            # Supabase + CMS

# Ressourcen
RAM_MB="${RAM_MB:-4096}"
SWAP_MB="${SWAP_MB:-1024}"
CORES="${CORES:-2}"

# Netzwerk
BRIDGE="${BRIDGE:-vmbr0}"
IP="${IP:-dhcp}"               # "dhcp" ODER statisch z.B. "192.168.1.50/24"
GATEWAY="${GATEWAY:-}"         # nur bei statischer IP

# Öffentliche Domain hinter einem Reverse-Proxy (Caddy o.ä.) mit Pfad-Routing
# (/auth/* + /rest/* → :8000, Rest → :8080). Leer = LAN-Direktzugriff per IP:Port.
SITE_DOMAIN="${SITE_DOMAIN:-}"

# Zugang
SSH_PUBKEY_FILE="${SSH_PUBKEY_FILE:-$HOME/.ssh/id_ed25519.pub}"
ROOT_PASSWORD=""

# Repo ist öffentlich → Clone braucht KEIN Token.
# GIT_TOKEN nur setzen, wenn das CMS später per GIT_PUBLISH nach Gitea
# zurückschreiben soll (git push braucht Auth). Format: "tokenname:tokenwert".
GIT_TOKEN="${GIT_TOKEN:-}"
REPO_HOST="git.kgva.ch/karim/OPENBUREAU.git"
APP_DIR="/opt/openbureau"

# Admin (sieht/bearbeitet ALLE Beiträge). Wird auch als erster Login-User vorgeschlagen.
ADMIN_EMAIL="${ADMIN_EMAIL:-karim@gabrielevarano.ch}"

# Stack nach dem Setup direkt bauen + starten?
COMPOSE_UP="true"
##################################################################

say() { echo -e "\n\033[1;36m▸ $*\033[0m"; }

# --- 0. Interaktiv nachfragen (Enter = Default) --------------------------
# Übersprungen, wenn kein Terminal (z.B. CI) — dann gelten die Defaults oben
# bzw. vorab gesetzte Umgebungsvariablen.
if [ -t 0 ]; then
  echo "OPENBUREAU LXC-Setup — Enter übernimmt den Default in [Klammern]."
  read -rp "  Storage für die Disk         [${ROOTFS_STORAGE}]: " _x; ROOTFS_STORAGE="${_x:-$ROOTFS_STORAGE}"
  read -rp "  Netzwerk-Bridge              [${BRIDGE}]: " _x; BRIDGE="${_x:-$BRIDGE}"
  read -rp "  IP (dhcp | x.x.x.x/24)       [${IP}]: " _x; IP="${_x:-$IP}"
  [ "$IP" != "dhcp" ] && { read -rp "  Gateway: " GATEWAY; }
  read -rp "  Admin-E-Mail                 [${ADMIN_EMAIL}]: " _x; ADMIN_EMAIL="${_x:-$ADMIN_EMAIL}"
fi

# --- 1. Template sicherstellen -------------------------------------------
say "Suche aktuelles Debian-12-Template…"
pveam update >/dev/null || true
TEMPLATE="$(pveam available --section system \
  | awk '/debian-12-standard/{print $2}' | sort -V | tail -1)"
[ -n "$TEMPLATE" ] || { echo "Kein debian-12-Template gefunden."; exit 1; }
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then
  say "Lade Template $TEMPLATE…"
  pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
fi
TEMPLATE_REF="${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}"

# --- 2. Netzwerk ----------------------------------------------------------
if [ "$IP" = "dhcp" ]; then
  NET="name=eth0,bridge=${BRIDGE},ip=dhcp"
else
  [ -n "$GATEWAY" ] || { echo "Statische IP, aber GATEWAY leer."; exit 1; }
  NET="name=eth0,bridge=${BRIDGE},ip=${IP},gw=${GATEWAY}"
fi

# --- 3. Container erstellen ----------------------------------------------
say "Erstelle LXC $CTID ($HOSTNAME)…"
CREATE_ARGS=(
  "$CTID" "$TEMPLATE_REF"
  --hostname "$HOSTNAME"
  --cores "$CORES" --memory "$RAM_MB" --swap "$SWAP_MB"
  --rootfs "${ROOTFS_STORAGE}:${DISK_GB}"
  --net0 "$NET"
  --unprivileged 1
  --features "nesting=1,keyctl=1"
  --onboot 1
)
[ -n "$ROOT_PASSWORD" ] && CREATE_ARGS+=(--password "$ROOT_PASSWORD")
[ -f "$SSH_PUBKEY_FILE" ] && CREATE_ARGS+=(--ssh-public-keys "$SSH_PUBKEY_FILE")
pct create "${CREATE_ARGS[@]}"

say "Starte Container…"
pct start "$CTID"
sleep 5

# Clone-URL (mit Token, falls gesetzt)
if [ -n "$GIT_TOKEN" ]; then
  REPO_URL="https://${GIT_TOKEN}@${REPO_HOST}"
else
  REPO_URL="https://${REPO_HOST}"
fi

# --- 4. Provisionierung im Container -------------------------------------
say "Installiere Docker + Git, ziehe Repo, generiere Secrets…"
pct exec "$CTID" -- bash -euo pipefail -c "
  export DEBIAN_FRONTEND=noninteractive
  apt-get update -qq
  apt-get install -y -qq ca-certificates curl git openssl >/dev/null
  curl -fsSL https://get.docker.com | sh >/dev/null
  systemctl enable --now docker

  if [ ! -d '${APP_DIR}/.git' ]; then
    git clone --quiet '${REPO_URL}' '${APP_DIR}' || {
      echo 'WARN: Clone fehlgeschlagen (Token nötig?). Setup hier gestoppt.'; exit 0; }
  fi

  cd '${APP_DIR}/cms'
  if [ ! -f .env ]; then
    cp .env.example .env

    # Secrets generieren
    PW=\$(openssl rand -hex 32)
    JWT=\$(openssl rand -hex 32)
    sed -i \"s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=\${PW}|\" .env
    sed -i \"s|^JWT_SECRET=.*|JWT_SECRET=\${JWT}|\" .env

    # ANON_KEY + SERVICE_ROLE_KEY via Wegwerf-Node-Container ableiten
    KEYS=\$(docker run --rm -v \"\$PWD\":/w -w /w node:20-alpine \
             node scripts/generate-keys.mjs \"\$JWT\" 2>/dev/null)
    ANON=\$(echo \"\$KEYS\"    | sed -n 's/^ANON_KEY=//p')
    SVC=\$(echo \"\$KEYS\"     | sed -n 's/^SERVICE_ROLE_KEY=//p')
    sed -i \"s|^ANON_KEY=.*|ANON_KEY=\${ANON}|\" .env
    sed -i \"s|^SERVICE_ROLE_KEY=.*|SERVICE_ROLE_KEY=\${SVC}|\" .env

    # URLs setzen — bei gesetzter SITE_DOMAIN auf die öffentliche HTTPS-Domain
    # (Browser ruft /auth/* + /rest/* same-origin auf, der Proxy routet sie an
    # :8000), sonst auf die Container-IP fürs LAN.
    HOSTIP=\$(hostname -I | awk '{print \$1}')
    SITE_DOMAIN='${SITE_DOMAIN}'
    if [ -n \"\$SITE_DOMAIN\" ]; then
      SITE_URL=\"https://\$SITE_DOMAIN\"; API_URL=\"https://\$SITE_DOMAIN\"
    else
      SITE_URL=\"http://\${HOSTIP}:8080\"; API_URL=\"http://\${HOSTIP}:8000\"
    fi
    sed -i \"s|^SITE_URL=.*|SITE_URL=\${SITE_URL}|\" .env
    sed -i \"s|^API_EXTERNAL_URL=.*|API_EXTERNAL_URL=\${API_URL}|\" .env
    sed -i \"s|^ADMIN_EMAILS=.*|ADMIN_EMAILS=${ADMIN_EMAIL}|\" .env
    # Auf allen Interfaces lauschen, damit Reverse-Proxy bzw. LAN drankommen.
    sed -i \"s|^BIND_ADDR=.*|BIND_ADDR=0.0.0.0|\" .env
    # CORS auf die Browser-Origin (= SITE_URL) festnageln statt „*\".
    sed -i \"s|__CORS_ORIGIN__|\${SITE_URL}|g\" kong.yml
    echo 'OK: .env generiert.'
  fi

  # Der CMS-Container läuft als non-root (uid 1000). Das gemountete Repo muss
  # ihm gehören, damit Hugo public/ bauen und content/ schreiben kann.
  chown -R 1000:1000 '${APP_DIR}'

  if [ '${COMPOSE_UP}' = 'true' ]; then
    echo '→ Baue + starte Stack (dauert beim ersten Mal ein paar Minuten)…'
    docker compose up -d --build
  fi

  # Tägliches DB-Backup (3:15 Uhr) — Dialog-Daten liegen NUR in Postgres.
  printf 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n15 3 * * * root cd ${APP_DIR}/cms && bash scripts/backup-db.sh >> /var/log/openbureau-backup.log 2>&1\n' > /etc/cron.d/openbureau-backup
  echo 'OK: tägliches DB-Backup eingerichtet (/etc/cron.d/openbureau-backup).'
"

# --- 5. Abschluss --------------------------------------------------------
IPADDR="$(pct exec "$CTID" -- hostname -I 2>/dev/null | awk '{print $1}')"
say "Fertig. LXC $CTID läuft${IPADDR:+ unter $IPADDR}."

if [ -n "$SITE_DOMAIN" ]; then
cat <<EOF

Öffentlich: https://${SITE_DOMAIN}   (sobald der Reverse-Proxy auf ${IPADDR:-<ip>} zeigt)
  Caddy-Block:  ${SITE_DOMAIN} {
                  # Nur /auth/* muss public ans Gateway (Browser-Login). Daten
                  # laufen über /api/* (Node spricht kong intern an). /rest, /storage,
                  # /realtime NICHT exponieren — unnötige Angriffsfläche.
                  @auth path /auth/*
                  reverse_proxy @auth ${IPADDR:-<ip>}:8000
                  reverse_proxy ${IPADDR:-<ip>}:8080
                }
EOF
fi

cat <<EOF

Admin:    http://${IPADDR:-<ip>}:8080/admin/
Live:     http://${IPADDR:-<ip>}:8080/
Supabase: http://${IPADDR:-<ip>}:8000   (nur API-Gateway, keine Web-UI — / gibt 404, ist normal)

Login-User anlegen (im Container, nach dem Start):
  pct enter ${CTID}
  cd ${APP_DIR}/cms
  source .env
  curl -s -X POST "http://localhost:8000/auth/v1/admin/users" \\
    -H "apikey: \$SERVICE_ROLE_KEY" \\
    -H "Authorization: Bearer \$SERVICE_ROLE_KEY" \\
    -H "Content-Type: application/json" \\
    -d '{"email":"${ADMIN_EMAIL}","password":"DEIN-PASSWORT","email_confirm":true}'

Hinweise:
  • :8000 ist das Supabase-API-Gateway (Kong), keine Web-Oberfläche.
    Das Admin-Login (:8080/admin/) spricht im Hintergrund damit.
  • Für Domain/HTTPS: SITE_URL + API_EXTERNAL_URL in .env auf die
    öffentliche Adresse setzen und 'docker compose up -d --build' neu.
  • Logs:  pct enter ${CTID}; cd ${APP_DIR}/cms; docker compose logs -f
EOF
