<?php

use App\Jobs\PacedMail;
use App\Mail\DormantAccountWarningMail;
use App\Models\User;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;

/**
 * Eine Mail fährt über IHREN Mailer, nicht über den Standard-Mailer.
 *
 * Jede Mail dieses Systems wählt im Konstruktor ihren Mailer — `cp_mail_<typ>`
 * oder `cp_<zweck>`. Dahinter steht MailboxTransport: er sucht das Postfach,
 * dessen Adresse im Absender steht, meldet sich mit genau dessen Zugangsdaten
 * an, und er ist die Stelle, an der der Notschalter aus App\Support\MailDelivery
 * greift.
 *
 * `Mail::to(…)` löst den STANDARD-Mailer auf. Dessen queue() schreibt dann
 * `$view->mailer($this->name)` — der eigene Mailer der Mail wird durch 'smtp'
 * ersetzt, bevor der Auftrag überhaupt gebaut ist. Was danach abgeschickt wird,
 * kennt weder Postfach noch Schalter: es meldet sich mit den Zugangsdaten aus
 * der Konfiguration an, setzt aber den Absender aus der Mail, und ein Server,
 * der prüft, wem die Absenderadresse gehört, weist es ab („553 Sender address
 * rejected"). Genau das lief hier tagelang im Minutentakt — und eine
 * abgeschaltete Zustellung schaltete nichts ab.
 *
 * Deshalb beginnt jeder Versand mit `Mail::mailer($mail->mailer)`: dann
 * schreibt das Überschreiben denselben Wert zurück, den die Mail schon hatte.
 */
it('keeps the mailable own mailer when it is queued through Mail::mailer', function () {
    Queue::fake();

    $mail = new DormantAccountWarningMail(User::factory()->create(), 30);
    $chosen = $mail->mailer;

    expect($chosen)->not->toBeNull()
        ->and($chosen)->not->toBe(config('mail.default'));

    Mail::mailer($mail->mailer)->to('empfaenger@example.com')->queue($mail);

    Queue::assertPushed(
        PacedMail::class,
        fn (PacedMail $job) => $job->mailable->mailer === $chosen,
    );
});

/**
 * Der Gegenbeweis, damit die Regel oben nicht als Aberglaube gilt: dieselbe
 * Mail, ohne den benannten Mailer eingereiht, verliert ihn. Schlägt dieser Test
 * fehl, hat das Framework sein Verhalten geändert — dann darf die Regel weg,
 * vorher nicht.
 */
it('proves that Mail::to alone overwrites the mailable own mailer', function () {
    Queue::fake();

    $mail = new DormantAccountWarningMail(User::factory()->create(), 30);
    $chosen = $mail->mailer;

    Mail::to('empfaenger@example.com')->queue($mail);

    Queue::assertPushed(
        PacedMail::class,
        fn (PacedMail $job) => $job->mailable->mailer === config('mail.default')
            && $job->mailable->mailer !== $chosen,
    );
});

it('never dispatches a mail through Mail::to without naming the mailer', function () {
    $offenders = [];

    foreach (File::allFiles(app_path()) as $file) {
        if ($file->getExtension() !== 'php') {
            continue;
        }

        foreach (explode("\n", $file->getContents()) as $number => $line) {
            // Kommentare beschreiben die Falle — zwei Stellen im Repo tun genau
            // das an der Zeile, an der sie umgangen wird. Sie sind der Grund
            // für diese Regel, nicht ihr Verstoß.
            if (preg_match('#^\s*(//|\*|/\*)#', $line) === 1) {
                continue;
            }

            // Trifft beide Schreibweisen: `Mail::to(` und die voll
            // qualifizierte `\Illuminate\Support\Facades\Mail::to(`.
            if (preg_match('/(?<![\w\\\\])Mail::to\(/', $line) === 1) {
                $offenders[] = str_replace(base_path().'/', '', $file->getPathname()).':'.($number + 1);
            }
        }
    }

    expect($offenders)->toBe([]);
});
