<?php

use App\Models\Datacenter;
use App\Models\Operator;
use App\Services\Secrets\SecretVault;
use App\Support\OperatingMode;
use App\Support\Readiness;
use App\Support\Readiness\Check;
use App\Support\Settings;

/**
 * Die Bereitschaftsprüfung berichtet, was fehlt — und sagt dazu, was
 * kaputtgeht. Siehe BillingChecksTest für dieselbe Begründung.
 */
function onboardingCheck(string $key): ?Check
{
    return collect(Readiness::all())->firstWhere('key', $key);
}

it('needs at least one datacenter', function () {
    // create_datacenters_table selbst legt 'fsn'/'hel' als Vorgabe an — auch
    // in dieser Suite, da es sich um eine Migration und keinen Seeder
    // handelt. Erst geleert, damit dieser Test den echten leeren Zustand
    // prüft statt der Werkseinstellung dieser Installation.
    Datacenter::query()->delete();

    // ValidateHostInput ist der erste Schritt der Host-Kette und bricht ohne
    // Rechenzentrum ab — bevor überhaupt eine SSH-Verbindung versucht wird.
    expect(onboardingCheck('onboarding.datacenter')->satisfied)->toBeFalse();

    Datacenter::factory()->create();

    expect(onboardingCheck('onboarding.datacenter')->satisfied)->toBeTrue();
});

it('needs an ssh private key', function () {
    // Mode selbst gesetzt (Testisolation: CACHE_STORE=array wird zwischen
    // Testdateien nicht geleert), damit dieser Test nicht vom Rest der Zeile
    // abhängt, in der die Suite läuft.
    OperatingMode::set(OperatingMode::Live);

    // Diese Installation hat in .env tatsächlich einen SSH-Schlüssel
    // konfiguriert (CLUPILOT_SSH_PRIVATE_KEY_PATH), auf den SecretVault::get()
    // zurückfällt, solange kein Tresor-Eintrag existiert — direkt
    // zurückgesetzt, damit der Test nicht vom Entwicklerrechner abhängt.
    config()->set('provisioning.ssh.private_key', '');

    expect(onboardingCheck('onboarding.ssh_private_key')->satisfied)->toBeFalse();

    app(SecretVault::class)->put(
        'ssh.private_key',
        '-----BEGIN OPENSSH PRIVATE KEY-----',
        Operator::factory()->create(),
        OperatingMode::Live,
    );

    expect(onboardingCheck('onboarding.ssh_private_key')->satisfied)->toBeTrue();
});

it('needs a usable vault key', function () {
    // isUsable() statt eines bloßen filled()-Checks: SecretCipher warnt in
    // seinem eigenen Kommentar genau davor, eine zweite, schwächere Regel zu
    // bauen, die einen falsch geformten Schlüssel als gültig durchwinkt.
    config()->set('admin_access.secrets_key', '');
    expect(onboardingCheck('onboarding.secrets_key')->satisfied)->toBeFalse();

    config()->set('admin_access.secrets_key', base64_encode(str_repeat('a', 32)));
    expect(onboardingCheck('onboarding.secrets_key')->satisfied)->toBeTrue();
});

it('needs a usable vpn config key', function () {
    config()->set('admin_access.vpn_config_key', '');
    expect(onboardingCheck('onboarding.vpn_config_key')->satisfied)->toBeFalse();

    config()->set('admin_access.vpn_config_key', base64_encode(str_repeat('b', 32)));
    expect(onboardingCheck('onboarding.vpn_config_key')->satisfied)->toBeTrue();
});

it('needs all three wireguard values, not just some', function () {
    // Zwei von drei ist kein halber Tunnel, sondern gar keiner. Subnet wird
    // bewusst direkt über config() geprüft statt über Settings/
    // ProvisioningSettings (siehe deren eigener Kopfkommentar: der Compose-
    // Stack liest denselben Schlüssel beim Containerstart) — und hier im Test
    // ebenso direkt zurückgesetzt, damit das Ergebnis nicht von den echten
    // WireGuard-Werten dieser Installation abhängt.
    config()->set('provisioning.wireguard.hub_public_key', '');
    config()->set('provisioning.wireguard.endpoint', '');
    config()->set('provisioning.wireguard.subnet', '');

    expect(onboardingCheck('onboarding.wg_hub')->satisfied)->toBeFalse();

    Settings::set('provisioning.wg_hub_pubkey', 'abc=');
    Settings::set('provisioning.wg_endpoint', '198.51.45.9:51820');

    expect(onboardingCheck('onboarding.wg_hub')->satisfied)->toBeFalse();

    config()->set('provisioning.wireguard.subnet', '10.66.0.0/24');

    expect(onboardingCheck('onboarding.wg_hub')->satisfied)->toBeTrue();
});

it('names what breaks for every onboarding check, not just what is missing', function () {
    foreach ([
        'onboarding.ssh_private_key',
        'onboarding.secrets_key',
        'onboarding.vpn_config_key',
        'onboarding.wg_hub',
        'onboarding.datacenter',
    ] as $key) {
        expect(onboardingCheck($key)->breaks)->not->toBe('');
    }
});
