<?php // tests/Feature/Admin/MailRoutingTest.php

use App\Models\Mailbox;
use App\Services\Mail\MailCatalogue;
use App\Services\Mail\MailPurpose;
use App\Services\Mail\MailRoute;
use App\Support\Settings;
use Illuminate\Support\Facades\Mail;

// Blank slate statt der migrationseigenen fuenf (no-reply, support, billing,
// office, info): drei der Tests unten legen selbst ein Postfach mit dem
// Schluessel 'no-reply' an, und das kollidiert sonst mit mailboxes.key's
// Unique-Constraint gegen die von RefreshDatabase stehen gelassene Saat. Der
// Helfer existiert schon in tests/Pest.php, genau fuer diesen Fall (siehe
// tests/Feature/Mail/MailSettingsPageTest.php).
beforeEach(fn () => clearMailboxSeed());

it('schickt ohne Eintrag genau dorthin, wo die Mail vorher hinging', function () {
    // Der wichtigste Test dieser Aufgabe: der Umbau darf am heutigen Verhalten
    // NICHTS ändern, solange niemand etwas einstellt. Sonst wandern beim
    // Ausrollen still die Rechnungen in ein anderes Postfach.
    $system = Mailbox::factory()->create(['key' => 'no-reply', 'active' => true]);
    Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), 'no-reply');

    expect(MailRoute::purposeOrMailbox('new-device', MailPurpose::SYSTEM)?->id)
        ->toBe($system->id);
});

it('legt eine einzelne Mailart auf ein anderes Postfach', function () {
    Mailbox::factory()->create(['key' => 'no-reply', 'active' => true]);
    $info = Mailbox::factory()->create(['key' => 'info', 'active' => true]);
    Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), 'no-reply');
    Settings::set(MailRoute::settingKey('new-device'), 'info');

    // Und nur diese eine: der Nachbar bleibt, wo er war. Mit einem EIGENEN
    // Postfach fuer Abrechnung — ohne das waere die Zusicherung leer, weil der
    // Resolver dann null liefert und null nun einmal nicht 'info' ist.
    $billing = Mailbox::factory()->create(['key' => 'billing', 'active' => true]);
    Settings::set(MailPurpose::settingKey(MailPurpose::BILLING), 'billing');

    expect(MailRoute::purposeOrMailbox('new-device', MailPurpose::SYSTEM)?->id)->toBe($info->id)
        ->and(MailRoute::purposeOrMailbox('invoice', MailPurpose::BILLING)?->id)->toBe($billing->id);
});

it('faellt auf den Zweck zurueck, wenn das eingetragene Postfach abgeschaltet ist', function () {
    // Eine Mail, die nicht rausgeht, ist schlimmer als eine aus der zweitbesten
    // Adresse.
    Mailbox::factory()->create(['key' => 'no-reply', 'active' => true]);
    Mailbox::factory()->create(['key' => 'info', 'active' => false]);
    Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), 'no-reply');
    Settings::set(MailRoute::settingKey('new-device'), 'info');

    expect(MailRoute::purposeOrMailbox('new-device', MailPurpose::SYSTEM)?->key)->toBe('no-reply');
});

it('kennt zu jeder Mailart einen Vorgabe-Zweck', function () {
    // Ohne Vorgabe stünde eine Mailart ohne Postfach da, sobald jemand die
    // Wegwahl leert.
    foreach (MailCatalogue::all() as $key => $eintrag) {
        expect($eintrag['purpose'])->toBeIn(MailPurpose::ALL, "[{$key}] hat keinen gueltigen Vorgabe-Zweck.");
        expect($eintrag['label'])->not->toBe('');
    }
});

// ---- Die Wegwahl verschiebt das KONTO, nicht nur den Absender ----

it('meldet sich mit gesetzter Wegwahl beim Konto des gewaehlten Postfachs an', function () {
    // Der Umschlag folgte der Wegwahl, die SMTP-Sitzung nicht: `From: info@`
    // ging durch die Anmeldung von `no-reply@`. Ein Server, der prueft, ob ein
    // Konto seine Absenderadresse besitzt, weist das ab ("553 5.7.1 Sender
    // address rejected") — und dann verschwindet ausgerechnet die Mail, die der
    // Betreiber gerade umgelegt hat.
    config()->set('admin_access.secrets_key', 'base64:'.base64_encode(random_bytes(32)));
    config()->set('mail.default', 'smtp'); // Zustellung an, wie im Betrieb
    Settings::set('mail.host', 'mail.example.test');
    Settings::set('mail.port', 587);

    Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com', 'active' => true]);
    Mailbox::factory()->create(['key' => 'info', 'address' => 'info@clupilot.com', 'active' => true]);
    Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), 'no-reply');

    $mailer = MailCatalogue::mailer('security-block');

    // Ohne Eintrag: das Postfach des Zwecks, genau wie bisher.
    expect((string) Mail::mailer($mailer)->getSymfonyTransport())
        ->toContain('no-reply@clupilot.com');

    Settings::set(MailRoute::settingKey('security-block'), 'info');

    // Frisch aufloesen: der MailManager haelt einen einmal gebauten Mailer.
    Mail::forgetMailers();

    expect((string) Mail::mailer($mailer)->getSymfonyTransport())
        ->toContain('info@clupilot.com')
        ->not->toContain('no-reply@clupilot.com');

    // Und die Nachbarn bleiben, wo sie waren — die Wegwahl gilt fuer GENAU
    // eine Mailart, auch was das Konto angeht.
    expect((string) Mail::mailer(MailCatalogue::mailer('new-device'))->getSymfonyTransport())
        ->toContain('no-reply@clupilot.com');
});

it('fuehrt die Liste der Mailarten nur an EINER Stelle', function () {
    // Zwei Listen bedeuten, dass die zweite beim siebzehnten Mail vergessen
    // wird. Die Vorschau muss aus dem Katalog lesen.
    expect(array_keys(app(\App\Services\Mail\MailPreviews::class)->all()))
        ->toEqualCanonicalizing(array_keys(MailCatalogue::all()));
});
