<?php

use App\Livewire\Admin\MailPace;
use App\Mail\InvoiceMail;
use App\Mail\ResetPasswordMail;
use App\Services\Mail\MailLane;
use App\Support\Settings;
use Illuminate\Support\Facades\Lang;
use Livewire\Livewire;

/**
 * Die Sicht auf die drei Spuren, und der Notschalter davor.
 *
 * `mail.manage` ist dieselbe Fähigkeit wie auf admin/mail (App\Livewire\
 * Admin\Mail) — dort liegen die anderen Maileinstellungen, und wer die lesen
 * und ändern darf, darf auch sehen, was in den Spuren wartet, und die Drossel
 * abstellen.
 */
it('zeigt jede Spur mit ihrem Takt und dem, was wartet', function () {
    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->assertSee(MailLane::DIRECT)
        ->assertSee(MailLane::URGENT)
        ->assertSee(MailLane::CALM);
});

it('laesst den Betreiber eine Mail verschieben', function () {
    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->call('move', InvoiceMail::class, MailLane::URGENT);

    expect(MailLane::for(InvoiceMail::class))->toBe(MailLane::URGENT);
});

it('verschiebt eine gesperrte Mail nicht, auch nicht ueber die Komponente', function () {
    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->call('move', ResetPasswordMail::class, MailLane::CALM);

    expect(MailLane::for(ResetPasswordMail::class))->toBe(MailLane::DIRECT);
});

it('zeigt eine gesperrte Klasse als gesperrt statt mit einem Auswahlfeld', function () {
    // Das Schloss ist nur die Höflichkeit vor der serverseitigen Ablehnung im
    // Test darüber — aber eine Auswahl, die eine gesperrte Klasse anbietet,
    // wäre die Einladung zu einem Klick, der ohnehin nichts bewirkt.
    $html = Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->assertSee(__('mail_pace.class.ResetPasswordMail'))
        ->html();

    expect($html)->not->toContain("move('".ResetPasswordMail::class."'");
});

it('schaltet die Drossel ab und wieder an', function () {
    $component = Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->call('togglePace');

    expect(Settings::bool('mail.pace.enabled', true))->toBeFalse();

    $component->call('togglePace');

    expect(Settings::bool('mail.pace.enabled', true))->toBeTrue();
});

/**
 * Die zweite Hälfte der Untergrenze aus MailPaceServiceProvider::
 * mindestensEins() — die dortige liest nur ab, was hier gar nicht erst
 * gespeichert werden darf. Ohne diese Prüfung käme eine eingetippte 0 durch
 * bis zur Einstellung und würde erst beim nächsten Auftrag an der Lesestelle
 * abgefangen, nachdem der Betreiber schon „gespeichert" gesehen hat.
 */
it('verweigert ein Kontingent von null oder weniger', function () {
    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->set('urgentCount', 0)
        ->call('savePace')
        ->assertHasErrors(['urgentCount' => 'min']);

    expect(Settings::get('mail.pace.urgent.count'))->toBeNull();
});

it('verweigert ein Fenster von null Minuten', function () {
    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->set('calmMinutes', 0)
        ->call('savePace')
        ->assertHasErrors(['calmMinutes' => 'min']);

    expect(Settings::get('mail.pace.calm.minutes'))->toBeNull();
});

it('speichert einen gueltigen Takt fuer beide gedrosselten Spuren', function () {
    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(MailPace::class)
        ->set('urgentCount', 12)
        ->set('urgentMinutes', 3)
        ->set('calmCount', 7)
        ->set('calmMinutes', 9)
        ->call('savePace')
        ->assertHasNoErrors();

    expect(Settings::get('mail.pace.urgent.count'))->toBe(12)
        ->and(Settings::get('mail.pace.urgent.minutes'))->toBe(3)
        ->and(Settings::get('mail.pace.calm.count'))->toBe(7)
        ->and(Settings::get('mail.pace.calm.minutes'))->toBe(9);
});

/**
 * ── Namen statt Klassennamen ──────────────────────────────────────────────
 *
 * Die Seite zeigte `class_basename()`: „DormantAccountWarningMail" stand
 * dort, wo der Betreiber „Konto ohne Paket wird gelöscht" sucht. Ein
 * Klassenname ist eine Auskunft über den Bauplan, keine über die Mail.
 */
it('nennt jede Mailklasse bei ihrem Namen, nicht bei ihrer Klasse', function () {
    $html = Livewire::actingAs(operator('Owner'), 'operator')->test(MailPace::class)->html();

    foreach (array_keys(MailLane::all()) as $class) {
        $kurz = class_basename($class);

        expect(Lang::has('mail_pace.class.'.$kurz))
            ->toBeTrue("Für {$kurz} fehlt ein Name in lang/de/mail_pace.php.");

        // Der Klassenname darf auch nicht mehr durchscheinen — er steht nur
        // noch im wire:key und im Wert des Auswahlfelds, beides mit vollem
        // Namensraum davor.
        expect($html)->not->toContain('>'.$kurz.'<');
    }
});

it('führt für jede Mailklasse denselben Namen in beiden Sprachen', function () {
    // Eine Sprache ohne den Eintrag zeigte still den Schlüssel selbst —
    // „mail_pace.class.InvoiceMail" mitten in einer Tabelle.
    $de = require lang_path('de/mail_pace.php');
    $en = require lang_path('en/mail_pace.php');

    foreach (array_keys(MailLane::all()) as $class) {
        expect($de['class'])->toHaveKey(class_basename($class))
            ->and($en['class'])->toHaveKey(class_basename($class));
    }
});

it('sagt unter jeder Spur, was in ihr faehrt, statt ihren Warteschlangennamen zu wiederholen', function () {
    // Vorher stand dort „Ruhig / mail-ruhig" — dieselbe Auskunft zweimal, die
    // zweite in Kleinschrift. Der Warteschlangenname gehoert in die
    // --queue-Liste des Arbeiters, nicht auf die Seite, auf der jemand
    // entscheidet, was wie eilig ist.
    $html = Livewire::actingAs(operator('Owner'), 'operator')->test(MailPace::class)->html();

    foreach ([MailLane::DIRECT, MailLane::URGENT, MailLane::CALM] as $spur) {
        expect(Lang::has('mail_pace.lane_hint.'.$spur))->toBeTrue()
            ->and($html)->toContain(e(__('mail_pace.lane_hint.'.$spur)));
    }

    // Der rohe Name steht nur noch dort, wo er etwas bewirkt: im Wert der
    // Auswahlfelder der Zuordnung, nicht als sichtbarer Text.
    expect($html)->not->toContain('>'.MailLane::CALM.'<');
});
