<?php

use App\Livewire\Invoices;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Order;
use App\Models\User;
use App\Services\Billing\IssueInvoice;
use App\Support\CompanyProfile;
use Livewire\Livewire;

/**
 * The customer sees their own invoices, and only those.
 *
 * The page used to be a mock nobody took back out: five invented documents
 * numbered CP-2026-0003 to CP-2026-0007 — a prefix belonging to no series this
 * installation has ever configured — all marked paid, a rising spend curve and a
 * next charge of 198 € on a date somebody typed. Every signed-in customer saw it,
 * while the invoices we had really issued them, and really mailed them, appeared
 * nowhere in the portal at all.
 */
beforeEach(function () {
    CompanyProfile::put([
        'name' => 'CluPilot Cloud e.U.', 'address' => 'Dreherstraße 66/1/8',
        'postcode' => '1110', 'city' => 'Wien', 'vat_id' => 'ATU00000000',
    ]);
});

/** A portal customer with a signed-in user behind them. */
function invoiceCustomer(string $email): array
{
    $user = User::factory()->create(['email' => $email, 'email_verified_at' => now()]);
    $customer = Customer::factory()->create(['email' => $email, 'user_id' => $user->id]);

    return [$user, $customer];
}

function issuedFor(Customer $customer, int $chargedCents): Invoice
{
    return app(IssueInvoice::class)->forOrders($customer, collect([
        Order::factory()->create([
            'customer_id' => $customer->id,
            'amount_cents' => $chargedCents,
            'currency' => 'EUR',
            'status' => 'paid',
            'stripe_event_id' => 'cs_'.uniqid(),
        ]),
    ]));
}

it('lists the invoices this customer was actually issued, with their real numbers and totals', function () {
    [$user, $customer] = invoiceCustomer('own@invoices.test');

    $older = issuedFor($customer, 21480);
    $newer = issuedFor($customer, 23880);

    Livewire::actingAs($user)->test(Invoices::class)
        ->assertSee($older->number)
        ->assertSee($newer->number)
        // The number the customer was charged, off the document itself.
        ->assertSee('238,80')
        ->assertSee('214,80')
        // Newest first: the one somebody came here to fetch is the last one.
        ->assertViewHas('invoices', fn ($invoices) => $invoices->first()->is($newer))
        // And nothing invented. This was the mock's, and its prefix belongs to
        // no configured series.
        //
        // Hier stand einmal auch `assertDontSee('01.08.2026')` — das Datum aus
        // der Attrappe. Es hat am 1. August 2026 zugeschlagen: die echten
        // Rechnungen dieses Tests tragen das Ausstellungsdatum von heute, also
        // war die Zeichenkette plötzlich zu Recht auf der Seite. Eine
        // Zusicherung, die ein Datum verbietet, verbietet auch den Tag, an dem
        // es echt wird. Was die Attrappe wirklich ausmachte, war ihr Satz, und
        // den prüft der Test „says nothing at all about a next charge" nebenan
        // über 'Nächste Abbuchung' — stabil, weil er nirgends sonst entsteht.
        ->assertDontSee('CP-2026-0007');
});

it('never shows one customer another customer\'s invoice', function () {
    [$user] = invoiceCustomer('mine@invoices.test');
    [, $stranger] = invoiceCustomer('theirs@invoices.test');

    $theirs = issuedFor($stranger, 21480);

    Livewire::actingAs($user)->test(Invoices::class)
        ->assertDontSee($theirs->number)
        ->assertSee(__('invoices.empty'));
});

it('hands over the customer\'s own PDF and refuses everybody else\'s', function () {
    [$user, $customer] = invoiceCustomer('pdf@invoices.test');
    [$stranger] = invoiceCustomer('nosy@invoices.test');

    $invoice = issuedFor($customer, 21480);

    $this->actingAs($user)->get(route('invoices.pdf', $invoice->uuid))
        ->assertOk()
        ->assertHeader('content-type', 'application/pdf');

    // Checked in the query, not by leaving the link off the page: a URL anybody
    // can type is not made private by not printing it.
    $this->actingAs($stranger)->get(route('invoices.pdf', $invoice->uuid))->assertNotFound();
});

it('does not hand an invoice to somebody who is not signed in', function () {
    [, $customer] = invoiceCustomer('guarded@invoices.test');

    $invoice = issuedFor($customer, 21480);

    $this->get(route('invoices.pdf', $invoice->uuid))->assertRedirect('/login');
});

it('says nothing at all about a next charge nobody has computed', function () {
    [$user, $customer] = invoiceCustomer('nofuture@invoices.test');
    issuedFor($customer, 21480);

    // The mock announced "Nächste Abbuchung 198 € am 01.08.2026" to every
    // customer on the platform. What Stripe will take next cycle depends on
    // prorations, account credit and discounts, and nothing here works it out —
    // so the page says nothing rather than guessing.
    $html = Livewire::actingAs($user)->test(Invoices::class)->html();

    expect($html)->not->toContain('Nächste Abbuchung')
        ->and($html)->not->toContain('Ausgaben');
});

it('marks a cancellation so it cannot be mistaken for a second charge', function () {
    [$user, $customer] = invoiceCustomer('storno@invoices.test');

    $original = issuedFor($customer, 21480);
    $storno = app(IssueInvoice::class)->cancelling($original);

    Livewire::actingAs($user)->test(Invoices::class)
        ->assertSee($storno->number)
        ->assertSee(__('invoices.storno'));
});
