<?php // tests/Feature/Cancellation/RemindEndingServicesTest.php

use App\Mail\ServiceEndingSoonMail;
use App\Models\Instance;
use App\Support\ProvisioningSettings;
use Illuminate\Support\Facades\Mail;

it('erinnert sieben Tage vor dem Ende', function () {
    Mail::fake();
    $instance = Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addDays(6),
    ]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertQueued(ServiceEndingSoonMail::class);
    expect($instance->fresh()->export_reminded_at)->not->toBeNull();
});

it('erinnert auch, wenn das Ende genau in sieben Tagen liegt', function () {
    // Die obere Einschlussgrenze, gegenüber dem unteren Rand unten: die
    // Auswahl ist "höchstens sieben Tage", also gehört der siebte Tag noch
    // dazu, nicht erst der sechste.
    Mail::fake();
    Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addDays(7),
    ]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertQueued(ServiceEndingSoonMail::class);
});

it('erinnert nicht zweimal', function () {
    // Ein täglicher Zeitplan würde die Erinnerung sonst an jedem der
    // restlichen Tage erneut schicken. Eine Erinnerung im Sechserpack liest
    // sich als Mahnung.
    Mail::fake();
    Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addDays(6),
        'export_reminded_at' => now()->subHour(),
    ]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertNothingQueued();
});

it('erinnert nicht, wenn das Ende noch weit weg ist', function () {
    Mail::fake();
    Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addDays(30),
    ]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertNothingQueued();
});

it('erinnert nicht mehr, wenn das Ende schon vorbei ist', function () {
    // Kein akademischer Rand: EndInstanceService lässt einen DNS-Fehler
    // bewusst durch, eine gekündigte Instanz mit abgelaufener Frist kann also
    // real tagelang stehenbleiben, bis der stündliche Lauf durchkommt. Genau
    // dann darf keine Erinnerung mehr ausgehen — die Tür ist zu, und eine
    // Aufforderung zum Selbst-Herunterladen wäre eine Aufforderung ins Leere.
    Mail::fake();
    Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->subHour(),
    ]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertNothingQueued();
});

it('erinnert eine Instanz, die gar nicht gekündigt wurde, nicht', function () {
    Mail::fake();
    Instance::factory()->create(['status' => 'active', 'service_ends_at' => now()->addDays(6)]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertNothingQueued();
});

it('erinnert auch dann, wenn das Ende schon in wenigen Stunden ist', function () {
    // Der wichtigste Fall und der, den ein "genau sieben Tage"-Vergleich
    // verfehlt: eine Instanz, die zwischen zwei Läufen durchgerutscht ist,
    // oder eine, die mit kurzer Frist gekündigt wurde. Lieber spät erinnern
    // als gar nicht — ab dem Laufzeitende kommt der Kunde nicht mehr hinein.
    Mail::fake();
    Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addHours(3),
    ]);

    $this->artisan('clupilot:remind-ending-services')->assertSuccessful();

    Mail::assertQueued(ServiceEndingSoonMail::class);
});

it('trägt in der Mail das Datum und den Weg zum Selbst-Herunterladen', function () {
    $instance = Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addDays(6),
        'export_wish' => false,
    ]);

    $text = (new ServiceEndingSoonMail($instance))->render();

    // Kein roher Schlüssel, und die zwei Dinge, um die es geht: ab wann ist
    // zu, und wie komme ich vorher an meine Sachen — die Adresse selbst muss
    // also wirklich im Text stehen, nicht nur der Knopf, der theoretisch
    // hinführen könnte.
    expect($text)->not->toContain('service_ending.')
        ->and($text)->toContain($instance->service_ends_at->local()->isoFormat('LL'))
        ->and($text)->toContain('https://'.$instance->address(ProvisioningSettings::dnsZone()));
});

it('behauptet keinen Vorgang, den niemand ausfuehrt', function () {
    // W1: der Satz stand im Präsens und sagte, wir bereiteten bereits einen
    // Export vor. Es gibt keinen — er hängt an einem Speicherserver, den es
    // noch nicht gibt. Was stimmt, ist: der Wunsch ist vermerkt, und es
    // meldet sich jemand.
    $instance = Instance::factory()->create([
        'status' => 'cancellation_scheduled',
        'service_ends_at' => now()->addDays(6),
        'export_wish' => true,
    ]);

    $text = (new ServiceEndingSoonMail($instance))->render();

    expect($text)->toContain('vermerkt')
        ->and($text)->not->toContain('bereiten wir zusätzlich einen für Sie vor');
});
