#!/bin/sh
# Container-Start:
#   1) Auf DB warten
#   2) Auto-Baseline für bestehende DBs (db-push-Ära ohne _prisma_migrations)
#   3) `prisma migrate deploy` (idempotent, datenerhaltend)
#   4) Auto-Seed bei leerer User-Tabelle (oder RUN_SEED=true)
# Neue Schema-Änderung anlegen (lokal, im Dev): npm run schema:sync
set -e

# DATABASE_URL aus DB_*-Komponenten bauen, falls nicht explizit gesetzt.
# Wichtig: encodeURIComponent für DB_USER + DB_PASSWORD, damit Sonderzeichen
# wie $, !, #, @, :, / etc. nicht die URL-Authority-Syntax brechen.
# Wir nutzen node-eval (ist eh installiert), kein extra-Tool wie jq nötig.
if [ -z "$DATABASE_URL" ] && [ -n "$DB_USER" ] && [ -n "$DB_PASSWORD" ] && [ -n "$DB_NAME" ]; then
  DATABASE_URL=$(node -e "
    const u = encodeURIComponent(process.env.DB_USER);
    const p = encodeURIComponent(process.env.DB_PASSWORD);
    const h = process.env.DB_HOST || 'db';
    const port = process.env.DB_PORT || '3306';
    const n = process.env.DB_NAME;
    process.stdout.write(\`mysql://\${u}:\${p}@\${h}:\${port}/\${n}\`);
  ")
  export DATABASE_URL
  echo "[entrypoint] DATABASE_URL aus DB_*-Komponenten gebaut (host=${DB_HOST:-db})"
fi

echo "[entrypoint] Warte auf Datenbank…"
# Erst auf DB-Verfügbarkeit warten via einfachem Connect-Check.
# Wir nutzen Prisma's interne Engine, kein extra mysql-client nötig.
TRIES=30
until node -e "
  const { PrismaClient } = require('@prisma/client');
  const p = new PrismaClient();
  p.\$queryRaw\`SELECT 1\`
    .then(() => p.\$disconnect().then(() => process.exit(0)))
    .catch(() => process.exit(1));
" 2>/dev/null; do
  TRIES=$((TRIES - 1))
  if [ "$TRIES" -le 0 ]; then
    echo "[entrypoint] DB nicht erreichbar – Abbruch"
    exit 1
  fi
  echo "[entrypoint] DB noch nicht bereit – retry in 2s ($TRIES Versuche übrig)"
  sleep 2
done
echo "[entrypoint] DB erreichbar"

# Auto-Baseline: Wenn die DB Anwendungs-Tabellen enthält (z.B. User), aber noch
# keine _prisma_migrations-Tabelle, dann ist es eine "alte" DB, die früher mit
# `prisma db push` synced wurde. Wir markieren 0_init als bereits angewendet,
# damit `migrate deploy` nicht versucht, alle Tabellen nochmal anzulegen.
NEEDS_BASELINE=$(node -e "
  const { PrismaClient } = require('@prisma/client');
  const p = new PrismaClient();
  (async () => {
    try {
      const dbName = process.env.DB_NAME;
      const tables = await p.\$queryRawUnsafe(
        \`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?\`,
        dbName
      );
      const names = tables.map(t => t.TABLE_NAME);
      const hasMigrations = names.includes('_prisma_migrations');
      const hasUserTable  = names.includes('User');
      // Existing DB (User da) ohne Migrations-Tracking => Baseline nötig
      if (hasUserTable && !hasMigrations) process.stdout.write('yes');
      else process.stdout.write('no');
    } catch (e) {
      process.stdout.write('no');
    } finally {
      await p.\$disconnect();
    }
  })();
" 2>/dev/null)

if [ "$NEEDS_BASELINE" = "yes" ]; then
  echo "[entrypoint] Bestehende DB ohne Migrations-Tracking erkannt – markiere 0_init als angewendet (Baseline)"
  npx prisma migrate resolve --applied 0_init || echo "[entrypoint] Baseline fehlgeschlagen – fahre trotzdem fort"
fi

# Migrations anwenden (idempotent: bereits angewendete werden übersprungen).
# Im Gegensatz zu `db push` löscht `migrate deploy` keine Daten — Schema-
# Änderungen werden über versionierte Migrations-Files unter prisma/migrations/
# eingespielt. Neue Migration anlegen mit: npm run schema:sync (lokal, dev).
echo "[entrypoint] Wende Migrations an…"
if ! npx prisma migrate deploy; then
  echo "[entrypoint] migrate deploy fehlgeschlagen – Abbruch"
  exit 1
fi
echo "[entrypoint] DB-Schema aktuell"

# Pentest 53.3 (2026-06-01): wenn ein veraltetes Image gestartet wird
# (kein `docker compose build` nach Schema-Änderung), fehlten neue Felder
# wie `areaCode` im generierten Prisma-Client → PUT/POST crash. `prisma
# generate` am Start regeneriert den Client gegen das aktuelle Schema
# und kostet ~5–10 s – tradeoff für Robustheit.
echo "[entrypoint] Prisma-Client regenerieren (falls Image älter als Schema)…"
npx prisma generate || echo "[entrypoint] prisma generate fehlgeschlagen – nicht kritisch, Client bleibt aus Image"

# Auto-Seed: wenn die User-Tabelle leer ist (= Erstinstallation), automatisch seeden.
# RUN_SEED=true erzwingt Seed auch bei nicht-leerer DB (z.B. nach Reset).
USER_COUNT=$(node -e "
  const { PrismaClient } = require('@prisma/client');
  const p = new PrismaClient();
  p.user.count()
    .then((n) => { process.stdout.write(String(n)); process.exit(0); })
    .catch(() => { process.stdout.write('-1'); process.exit(0); });
" 2>/dev/null)

RAN_SEED=false
if [ "${RUN_SEED:-false}" = "true" ]; then
  echo "[entrypoint] RUN_SEED=true – seede DB (Force)"
  if npx prisma db seed; then RAN_SEED=true; else echo "[entrypoint] Seed fehlgeschlagen oder schon gelaufen – ignoriert"; fi
elif [ "$USER_COUNT" = "0" ]; then
  echo "[entrypoint] DB ist leer (User-Count=0) – Auto-Seed wird ausgeführt"
  if npx prisma db seed; then RAN_SEED=true; else echo "[entrypoint] Auto-Seed fehlgeschlagen – ignoriert"; fi
else
  echo "[entrypoint] DB enthält $USER_COUNT User – kein Seed nötig"
fi

# Eingebaute Factory-Defaults nach Erstinstallation einspielen.
# Das ist die Werkseinstellung für neue VMs: PDF-Vorlagen, Anbieter, Tarife,
# HTML-Templates – alles aus /app/factory-defaults-builtin/. Erfolgt nur wenn
# der Auto-Seed gerade lief (= frische DB), sonst werden Updates auf
# bestehenden Installationen nicht ungewollt überschrieben.
if [ "$RAN_SEED" = "true" ] && [ -d /app/factory-defaults-builtin ] \
   && [ -n "$(ls -A /app/factory-defaults-builtin 2>/dev/null | grep -v -E '^(README\.md|\.gitkeep)$')" ]; then
  echo "[entrypoint] Spiele eingebaute Factory-Defaults ein…"
  FACTORY_DEFAULTS_DIR=/app/factory-defaults-builtin npx tsx scripts/seed-factory-defaults.ts \
    || echo "[entrypoint] Factory-Defaults-Seed fehlgeschlagen – ignoriert"
fi

# Permissions + Rollen-Sync: Stellt sicher, dass nachträglich hinzugefügte
# Permissions (z.B. audit:read auf der DSGVO-Rolle) auch auf bestehenden
# DBs ankommen. Seed läuft NICHT auf nicht-leeren DBs, daher würden alte
# Installationen sonst mit unvollständigen Role-Perms laufen. Idempotent,
# fasst keine Stammdaten / User / Verträge an.
echo "[entrypoint] Rollen + Permissions synchronisieren…"
npx tsx prisma/sync-roles.ts \
  || echo "[entrypoint] Role-Sync fehlgeschlagen – nicht kritisch"

# Datenbereinigung: XSS-Strings aus Customer/User-Stringfeldern strippen,
# nicht-whitelisted AppSettings entfernen, Pentest-Marker melden (Default
# nur warnen; CLEANUP_PURGE_PENTEST=true löscht markierte Records).
# Idempotent – läuft bei jedem Container-Start ohne Risiko.
echo "[entrypoint] Datenbereinigung läuft…"
npx tsx prisma/cleanup-xss-and-mass-assignment.ts \
  || echo "[entrypoint] Cleanup übersprungen / fehlgeschlagen – nicht kritisch"

echo "[entrypoint] Starte Backend…"
exec "$@"
