#!/usr/bin/env bash
# ============================================================================
# Gemeinsame Ladereihenfolge fuer das RLS-Testschema
# ============================================================================
# Wird von ZWEI Aufrufern benutzt:
#   - scripts/rls-test/run.sh        (lokal, Postgres in Docker)
#   - .github/workflows/rls.yml      (CI, Postgres als Service)
#
# Warum eine gemeinsame Datei: Die Reihenfolge ist nicht beliebig (siehe die
# Begruendungen an den einzelnen Schritten). Zwei Kopien dieser Liste wuerden
# auseinanderlaufen, und der CI-Lauf pruefte dann ein anderes Schema als der
# lokale — mit dem Ergebnis, dass gruene Gates nichts mehr ueber die Policies
# aussagen, die tatsaechlich in Produktion stehen.
#
# Der Aufrufer stellt eine Funktion `psql_exec <datei>` bereit und setzt ROOT.
# ============================================================================

set -euo pipefail

load_rls_schema() {
  : "${ROOT:?ROOT muss gesetzt sein}"
  if ! declare -F psql_exec >/dev/null; then
    echo "psql_exec ist nicht definiert — der Aufrufer muss sie bereitstellen" >&2
    return 2
  fi

  echo "▶ bootstrap prerequisites"
  psql_exec "$ROOT/supabase/bootstrap/supabase-bootstrap-prerequisites.sql"

  echo "▶ prod schema + RLS policies"
  psql_exec "$ROOT/supabase/bootstrap/supabase-bootstrap-from-prod.sql"

  echo "▶ projects.department_id + reporting-flag (MIGRATIONS.md #65)"
  # Der Bootstrap-Dump (2026-05-07) kennt projects.department_id noch nicht.
  # Ohne diese Spalte scheitert weiter unten can_write_project() mit
  # 'column pr.department_id does not exist' — im CI-Lauf vom 04.08. exakt so
  # aufgetreten. Die Kette enthielt bisher nur RLS-Migrationen, nicht die
  # Schema-Migrationen, von denen sie abhaengen.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-projects-department-and-reporting-flag.sql"

  echo "▶ consultants.department_id (department single source, MIGRATIONS.md #89)"
  # Zweite fehlende Schema-Abhaengigkeit derselben Klasse: can_write_project()
  # joint consultants ueber department_id. Der Dump von 2026-05-07 fuehrt bei
  # consultants 21 Spalten, department_id ist nicht darunter.
  #
  # Reihenfolge ist zwingend: #89 nullt in Schritt 0 projects.department_id
  # ('UPDATE public.projects SET department_id = NULL WHERE ...'), bevor es die
  # generischen Abteilungen loescht. Laeuft #65 nicht vorher, bricht #89 mit
  # 'column "department_id" does not exist' ab — CI-Lauf 30935615398 vom 04.08.
  # In Produktion ist #65 folglich vor #89 angewendet worden; die Kette bildet
  # diese Reihenfolge jetzt ab. MIGRATIONS.md Abschnitt 7d ("NOT YET APPLIED")
  # ist an dieser Stelle veraltet — #89 haette sonst in Prod nicht laufen koennen.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-department-single-source-mo-codes.sql"

  echo "▶ Intake V1 (MIGRATIONS.md #57) + oeffentliche Einreichungs-Token"
  # Bringt intakes, fachbereich_users, consultant_availability, die vier
  # intake_field_*-Tabellen und project_phase_config. Wichtig fuer die
  # Sicherheitsabnahme ist die zweite Datei: sie legt intake_submission_tokens
  # an UND die SECURITY-DEFINER-Funktionen, die `consultants.role` als
  # Berechtigungsquelle lesen. Ohne sie laesst sich nicht pruefen, ob ein
  # Nutzer sich ueber consultants Rechte verschaffen kann.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-intake-v1-schema.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-intake-v1-public-submission-tokens.sql"

  echo "▶ consultants: Schreiben nur fuer admin/masteradmin (KAR-777, #85)"
  # Der Dump vom 2026-05-07 traegt hier noch consultants_insert/_update/_delete
  # mit USING (true) — jeder Angemeldete konnte sich selbst eine Zeile mit
  # role='masteradmin' anlegen. Diese Migration hat das geschlossen. Fehlt sie
  # in der Kette, prueft die Abnahme einen Stand, den es produktiv seit
  # KAR-777 nicht mehr gibt, und die Luecke faellt niemandem auf.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-consultants-write-rls-admin-only.sql"

  echo "▶ USING(true)-Schreibregeln schliessen, Tranche A (KAR-777, #91)"
  # Betrifft appointment_types, email_queue, master_data_import_jobs,
  # planning_projects, supplier_master_data. Tranche B-2 stand schon in der
  # Kette, A fehlte — dieselbe Fehlerklasse, nur eine Datei weiter.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-using-true-write-tranche-a.sql"

  echo "▶ Cross-Dept-Sichtbarkeit + Projekt-Freigaben (KAR-?, #95)"
  # Legt department_visibility und project_view_grants an und haengt die
  # Sichtbarkeit von projects daran. #115 baut darauf auf: sein
  # `project_id IN (SELECT id FROM public.projects)` meint genau diese Regeln.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-cross-dept-visibility-r40.sql"

  echo "▶ Release-Scope: RESTRICTIVE Policy + Guard-Trigger (KAR-783, #99)"
  # Die einzige RESTRICTIVE Policy im Schema. #117 behauptet in ihrem Kopf, sie
  # zu entfernen — ohne diese Datei in der Kette waere das eine unbelegte
  # Aussage: die Abnahme haette nie eine RESTRICTIVE Policy gesehen. Bringt
  # ausserdem projects.is_released und den Guard-Trigger, der Trigger bleibt
  # von #117 unberuehrt (sie fasst nur Policies an).
  psql_exec "$ROOT/supabase/migrations/supabase-migration-projects-released-scope.sql"

  echo "▶ user_profiles self-update guard (KAR-770) + department extension (KAR-785)"
  # Beide sind juenger als der Bootstrap-Dump vom 2026-05-07 (dort fehlt das
  # CREATE TRIGGER fuer guard_up_self_update) und muessen in DIESER Reihenfolge
  # nachgespielt werden: die zweite Datei ersetzt per CREATE OR REPLACE die
  # Funktion, die die erste anlegt.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-user-profiles-self-update-guard.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-user-profiles-guard-department.sql"

  echo "▶ documents owner/admin write policies (KAR-777, Tranche B-2)"
  # Der Dump traegt noch documents_insert/update/delete mit USING(true).
  psql_exec "$ROOT/supabase/migrations/supabase-migration-using-true-write-tranche-b2.sql"

  echo "▶ documents_select Duplikat-Policy-Fix (KAR-978)"
  # Entfernt das alte documents_select (USING (is_deleted = false)), das die
  # Scope-Pruefung von docs_select per OR neutralisiert hatte.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-documents-select-fix.sql"

  echo "▶ OEE v2 Schema (PR-A) + RLS-Verschaerfung + consultant/orphan-Fix"
  # supabase-migration-kadi-v2-rls-oee.sql (MIGRATIONS.md #47) wird BEWUSST
  # nicht geladen: sie dokumentiert einen frueheren, nie ausgelieferten
  # Schliessungsversuch. Beide legen oee_records_own/_admin an, ohne die
  # jeweils andere Fassung vorher zu entfernen — das kollidiert hart.
  # oee-v2-schema.sql nutzt CREATE INDEX CONCURRENTLY, deshalb darf dieser
  # Aufruf nicht in eine explizite Transaktion gewickelt werden.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-oee-v2-schema.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-oee-records-rls-tightening.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-oee-v2-rls-consultant-orphan-fix.sql"

  echo "▶ qaf-differences (KAR-799)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-qaf-differences.sql"

  echo "▶ qaf_process_mappings (KAR-103) + RLS-Fix (KAR-890)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-qaf-process-mappings.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-qaf-process-mappings-rls-fix.sql"

  echo "▶ PMO Phase 1 + drop-dead cleanup + team-write policies (FB-48/FB-49a)"
  # Spiegelt die Prod-Reihenfolge: die 3 toten PMO-Tabellen wurden am
  # 2026-07-03 entfernt (KAR-704). Ohne diesen Schritt liefen die
  # team-write-Policies gegen einen anderen Tabellenstand als in Produktion.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-pmo-phase-1.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-drop-dead-pmo-tables.sql"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-pmo-team-write-policies.sql"

  echo "▶ offline-sync updated_at (Modultabellen)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-offline-sync-updated-at.sql"

  echo "▶ value_stream_imports (KAR-971, QVS-P2)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-value-stream-imports.sql"

  echo "▶ wertstrom-scenarios (KAR-986, appliedt 2026-07-21)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-wertstrom-scenarios.sql"

  echo "▶ qaf-g60 Schema (Abhaengigkeit von #115)"
  # Reine Bestands-Schemaladung, KEINE G60-Weiterarbeit: das Rechtemodell unten
  # setzt Policies auch auf qaf_g60_tab und qaf_input_card. Ohne die Tabellen
  # bricht es ab. G60 bleibt fachlich deferred_by_product_owner.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-qaf-g60.sql"

  echo "▶ qaf-rls-project-access-model (appliedt 2026-07-30)"
  # Der wichtigste Nachtrag: ersetzt auf 17 qaf_*-Tabellen die alten
  # _own/_admin-Policies durch _read/_write plus can_write_project().
  # Ohne sie prueft die Testkette ein Rechtemodell, das seit dem 30.07. nicht
  # mehr produktiv ist — genau der Befund, der PR #428 blockiert hat.
  psql_exec "$ROOT/supabase/migrations/supabase-migration-qaf-rls-project-access-model.sql"

  echo "▶ qaf-summary-label-verification (KAR-996, appliedt 2026-07-31)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-qaf-summary-label-verification.sql"

  echo "▶ Test-Fixture"
  psql_exec "$ROOT/scripts/rls-test/setup.sql"
}

# ============================================================================
# Zweite Phase: das interne Zugriffsmodell (Produktentscheidung 04.08.2026).
# ============================================================================
# Bewusst NICHT Teil von load_rls_schema(): die Migration ist zum Zeitpunkt
# dieses Commits nicht in Produktion angewendet (operator-owned). Waere sie
# Teil der Kette, pruefte die erste Phase einen Stand, den es dort noch nicht
# gibt — und der Nachweis "die Kette reproduziert Produktion" waere hinfaellig.
#
# Der Ablauf ist deshalb zweistufig:
#   1. load_rls_schema() + die Isolationssuiten  → Stand wie in Produktion
#   2. apply_internal_open_access() + die Suite unten → Stand nach der Migration
apply_internal_open_access() {
  : "${ROOT:?ROOT muss gesetzt sein}"
  if ! declare -F psql_exec >/dev/null; then
    echo "psql_exec ist nicht definiert — der Aufrufer muss sie bereitstellen" >&2
    return 2
  fi

  echo "▶ internes Zugriffsmodell (angemeldet alles, anonym nichts)"
  psql_exec "$ROOT/supabase/migrations/supabase-migration-internal-open-access-model.sql"
}

# Die Testdateien, die gegen dieses Schema laufen. Ebenfalls gemeinsam gefuehrt,
# damit CI und lokaler Lauf nicht unterschiedliche Teilmengen pruefen.
RLS_TEST_FILES=(
  __tests__/security/rls-projects-isolation.test.ts
  __tests__/security/rls-project-children-isolation.test.ts
  __tests__/security/rls-user-scoped.test.ts
  __tests__/security/rls-qaf-differences-isolation.test.ts
  __tests__/security/rls-qaf-process-mappings-isolation.test.ts
  __tests__/security/rls-pmo-team-write-isolation.test.ts
  __tests__/security/rls-value-stream-imports-isolation.test.ts
  __tests__/security/rpc-create-value-stream-from-qaf.test.ts
  __tests__/offline/sync-updated-at-schema.test.ts
)

# Suite der zweiten Phase. Getrennt gefuehrt, weil sie das GEGENTEIL der
# Isolationssuiten behauptet: dort darf ein Fremder nichts, hier darf jeder
# Angemeldete alles. Beides in einem Lauf waere ein Widerspruch — die Trennung
# haelt fest, welcher Satz zu welchem Schema-Stand gehoert.
RLS_OPEN_MODEL_TEST_FILES=(
  __tests__/security/rls-internal-open-access.test.ts
)
