<?php

use App\Models\Mailbox;
use App\Models\MailTemplate;
use App\Models\Operator;
use App\Services\Mail\MailPurpose;
use App\Services\Secrets\SecretVault;
use App\Support\OperatingMode;
use App\Support\Readiness;
use App\Support\Readiness\Check;
use App\Support\Settings;

function deliveryCheck(string $key): ?Check
{
    return collect(Readiness::all())->firstWhere('key', $key);
}

/**
 * `mail.default = log` heißt: die VM läuft, der Beleg ist geschrieben, und die
 * Mail, die dem Kunden seine fertige Cloud ankündigt, liegt in einer Datei auf
 * dem Server. Der Kunde erfährt nie, dass er eine Cloud hat. Kein Fehler
 * taucht irgendwo auf.
 */
it('refuses to call an installation ready while mail goes to the log file', function () {
    config()->set('mail.default', 'log');

    expect(deliveryCheck('delivery.mailer_not_log')->satisfied)->toBeFalse();
});

/**
 * Fix-Runde (Befund 1): `!== 'log'` allein ist zu eng. MailboxTransport::
 * NON_DELIVERING kennt bereits die vollständige Liste — 'array' (der
 * MAIL_MAILER, den phpunit.xml der GANZEN Suite aufzwingt) und der
 * unkonfigurierte Fall (null) liefern genauso wenig zu wie 'log'. Eine
 * Prüfung, die nur 'log' kennt, war unter dem eigenen Testlauf grün, obwohl
 * hier nie eine Mail hinausginge — genau das Grün-aus-falschem-Grund, gegen
 * das diese Seite gebaut ist. Jeder Wert der Liste wird hier durchgegangen,
 * nicht nur der eine, den der ursprüngliche Vorfall zeigte.
 */
it('does not accept any value MailboxTransport itself treats as non-delivering', function (?string $default) {
    config()->set('mail.default', $default);

    expect(deliveryCheck('delivery.mailer_not_log')->satisfied)->toBeFalse();
})->with([
    'log' => ['log'],
    'array (the suite\'s own MAIL_MAILER)' => ['array'],
    'unset' => [null],
]);

it('accepts a real mailer', function () {
    config()->set('mail.default', 'smtp');

    expect(deliveryCheck('delivery.mailer_not_log')->satisfied)->toBeTrue();
});

it('needs a mailbox the transport would actually send from', function () {
    // Eine Migration seedet fünf Mailboxen (no-reply, support, billing,
    // office, info) für jede Installation — auch für diese Suite. Auf den
    // leeren Zustand zurückgesetzt, den dieser Test eigentlich prüft (siehe
    // clearMailboxSeed() in Pest.php).
    clearMailboxSeed();

    // CompleteProvisioning verschickt CloudReady SYNCHRON und wirft, wenn
    // MailboxResolver keine Mailbox findet — der letzte Schritt der
    // Bereitstellung scheitert dann, nachdem die Maschine schon läuft und der
    // Kunde schon bezahlt hat.
    expect(deliveryCheck('delivery.mailbox')->satisfied)->toBeFalse();

    // Bis zum 31.7.2026 stand hier `Mailbox::factory()->create()` und danach
    // `toBeTrue()`: IRGENDEIN Postfach genügte. Das war der Fehler. Gesendet
    // wird über das Postfach, das dem Zweck `system` zugeordnet ist — ein
    // angelegtes, aber unverknüpftes ändert daran nichts, und die Seite stand
    // grün, während jede „Passwort vergessen"-Mail in der Warteschlange starb.
    $box = Mailbox::factory()->create(['key' => 'nicht-verknuepft', 'active' => true]);

    expect(deliveryCheck('delivery.mailbox')->satisfied)->toBeFalse();

    Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), $box->key);

    expect(deliveryCheck('delivery.mailbox')->satisfied)->toBeTrue();
});

it('treats missing reply templates as a warning, never as a blocker', function () {
    // Eine Migration seedet einen Grundstock an Antwortvorlagen für jede
    // Installation — auch für diese Suite. Geleert, um den leeren Zustand zu
    // prüfen, den ein frisches Setup ohne diese Migration tatsächlich hätte.
    MailTemplate::query()->delete();

    expect(deliveryCheck('delivery.mail_templates')->satisfied)->toBeFalse();
    expect(deliveryCheck('delivery.mail_templates')->severity)->toBe(Check::SEVERITY_WARNING);

    MailTemplate::query()->create([
        'name' => 'Test Template',
        'subject' => 'Re: your question',
        'body' => 'Thanks for reaching out.',
        'sort' => 1,
        'active' => true,
    ]);

    expect(deliveryCheck('delivery.mail_templates')->satisfied)->toBeTrue();
});

it('treats a missing inbound mail password as a warning, never as a blocker', function () {
    OperatingMode::set(OperatingMode::Live);

    expect(deliveryCheck('delivery.inbound_mail_password')->satisfied)->toBeFalse();
    expect(deliveryCheck('delivery.inbound_mail_password')->severity)->toBe(Check::SEVERITY_WARNING);

    app(SecretVault::class)->put('inbound_mail.password', 'secret', Operator::factory()->create(), OperatingMode::Live);

    expect(deliveryCheck('delivery.inbound_mail_password')->satisfied)->toBeTrue();
});

it('names what breaks for every delivery check, not just what is missing', function () {
    foreach ([
        'delivery.mailer_not_log',
        'delivery.mailbox',
        'delivery.mail_templates',
        'delivery.inbound_mail_password',
    ] as $key) {
        expect(deliveryCheck($key)->breaks)->not->toBe('');
    }
});
