<?php

use App\Livewire\Admin\Mail as MailPage;
use App\Mail\Transport\MailboxTransport;
use App\Support\MailDelivery;
use App\Support\Readiness\DeliveryChecks;
use App\Support\Settings;
use Livewire\Livewire;

/**
 * Der Mailtransport war der letzte Wert des Mailstapels, der nur in der `.env`
 * stand. Host, Port und Verschlüsselung sind seit jeher Einstellungen; genau
 * `mail.default` nicht — und die Bereitschaftsseite meldete ihn als blockierend,
 * ohne sagen zu können, worauf man ihn stellen soll. „Irgendetwas, das nicht
 * `log` oder `array` ist" ist keine Anweisung, es ist die Aufgabe zurück an den
 * Betreiber.
 *
 * Es sind zwei Zustände, nicht eine Treiberauswahl: zustellen oder nicht. Was
 * tatsächlich sendet, ist MailboxTransport mit den gespeicherten Serverdaten
 * und den Zugangsdaten je Postfach — `mail.default` entscheidet nur, ob er
 * delegiert oder ins Log schreibt.
 */
it('prefers the stored transport over the one in the server file', function () {
    config()->set('mail.default', 'log');
    Settings::set('mail.transport', 'smtp');

    expect(MailDelivery::transport())->toBe('smtp')
        ->and(MailDelivery::delivers())->toBeTrue();
});

it('falls back to the server file when nothing is stored', function () {
    // Eine frische Installation hat die Zeile in der .env und keine
    // Einstellung — sie darf dadurch nicht anders senden als vorher.
    config()->set('mail.default', 'log');
    Settings::forget('mail.transport');

    expect(MailDelivery::transport())->toBe('log')
        ->and(MailDelivery::delivers())->toBeFalse();
});

it('lets the console turn delivery on, and the readiness check follows', function () {
    config()->set('mail.default', 'log');

    expect(satisfiedDeliveryCheck())->toBeFalse();

    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPage::class)
        ->set('confirmablePassword', 'password')
        ->call('confirmPassword')
        ->set('deliver', true)
        ->call('saveServer')
        ->assertHasNoErrors();

    expect(Settings::get('mail.transport'))->toBe('smtp')
        ->and(satisfiedDeliveryCheck())->toBeTrue();
});

it('lets the console turn delivery off again, and says so', function () {
    Settings::set('mail.transport', 'smtp');

    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPage::class)
        ->set('confirmablePassword', 'password')
        ->call('confirmPassword')
        ->set('deliver', false)
        ->call('saveServer')
        ->assertHasNoErrors();

    expect(Settings::get('mail.transport'))->toBe('log')
        ->and(satisfiedDeliveryCheck())->toBeFalse();
});

it('actually stops the transport from sending when it is switched off', function () {
    // Die Zusicherung, die zählt: die Einstellung muss dort ankommen, wo die
    // Entscheidung wirklich fällt. Eine Anzeige, die „wird zugestellt" sagt,
    // während MailboxTransport weiter ins Log schreibt, wäre genau die grüne
    // Anzeige über roter Grundlage, die dieses Projekt schon zweimal hatte.
    config()->set('mail.default', 'smtp');
    Settings::set('mail.transport', 'log');

    expect((string) new MailboxTransport('system'))->toContain('log');
});

function satisfiedDeliveryCheck(): bool
{
    foreach (DeliveryChecks::all() as $check) {
        if ($check->key === 'delivery.mailer_not_log') {
            return $check->satisfied;
        }
    }

    throw new RuntimeException('delivery.mailer_not_log check is gone');
}
