<?php

use App\Models\Customer;
use App\Models\Instance;
use App\Models\Seat;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * Laedt eine frische Instanz der Wanderung bei jedem Aufruf.
 *
 * `require`, nicht `require_once`: PHP wertet den `return new class ...`-
 * Ausdruck bei jedem Aufruf neu aus, jeder Aufruf bekommt also seine eigene
 * Instanz.
 */
function loadSeatNextcloudColumnsMigration(): object
{
    return require database_path('migrations/2026_08_03_180000_add_nextcloud_columns_to_seats.php');
}

/**
 * Stellt den Vor-Wanderungs-Zustand nach: RefreshDatabase hat up() schon
 * einmal auf einer leeren seats-Tabelle laufen lassen, die vier Spalten
 * stehen also schon. Ein zweiter Schema::table()-Aufruf auf bereits
 * vorhandene Spalten wuerde scheitern — hier weg damit, Zeilen bleiben.
 */
function dropSeatNextcloudColumns(): void
{
    Schema::table('seats', fn ($table) => $table->dropColumn(['nc_username', 'nc_state', 'nc_error', 'nc_synced_at']));
}

it('verknuepft einen bestehenden Inhaber-Sitz mit dem entschluesselten Anmeldenamen, nicht mit dem Chiffretext', function () {
    // Genau die Zusicherung, die die Verschluesselungsfalle aus der
    // Nachbesserung fuer die Zukunft absichert: nc_admin_ref ist am
    // Instance-Modell 'encrypted' gecastet. Faellt Crypt::decryptString()
    // in der Wanderung wieder heraus, landet hier der Chiffretext statt
    // 'admin' — dieser Test bricht dann, nicht erst eine echte Instanz.
    $customer = Customer::factory()->create();
    Instance::factory()->for($customer)->create(['nc_admin_ref' => 'admin', 'status' => 'active']);
    $sitz = Seat::factory()->for($customer)->create(['role' => 'owner']);

    dropSeatNextcloudColumns();
    loadSeatNextcloudColumnsMigration()->up();

    $zeile = DB::table('seats')->where('id', $sitz->id)->first();

    expect($zeile->nc_username)->toBe('admin')
        ->and($zeile->nc_state)->toBe('synced');
});

it('kommt bei derselben Ausgangslage zum selben Ergebnis wie Seat::linkToInstanceAdmin()', function () {
    // Der Preis des Einfrierens: zwei Fassungen derselben Auswahl koennen
    // auseinanderdriften, ohne dass es jemand merkt. Die Erwartung wird
    // ueber die Modellmethode eingeholt, BEVOR die Wanderung dieselbe Zeile
    // ueber ihren eigenen, eingefrorenen Weg anfasst — derselbe Kunde,
    // dieselbe Instanz, derselbe Sitz, zwei Wege dorthin.
    //
    // Verglichen werden nur nc_username/nc_state, nicht der ganze
    // Datensatz: das rohe update() der Wanderung setzt updated_at nicht,
    // save() ueber das Modell schon — das ist gewollt (siehe andere
    // Nachbefuellungen im Bestand) und keine Abweichung, die dieser Test
    // aufdecken soll.
    $customer = Customer::factory()->create();
    Instance::factory()->for($customer)->create(['nc_admin_ref' => 'gleicher-name', 'status' => 'active']);
    $sitz = Seat::factory()->for($customer)->create(['role' => 'owner']);

    $sitz->linkToInstanceAdmin();
    $erwarteterUsername = $sitz->nc_username;
    $erwarteterState = $sitz->nc_state;

    dropSeatNextcloudColumns();
    loadSeatNextcloudColumnsMigration()->up();

    $zeile = DB::table('seats')->where('id', $sitz->id)->first();

    expect($zeile->nc_username)->toBe($erwarteterUsername)
        ->and($zeile->nc_state)->toBe($erwarteterState);
});
