<?php

namespace App\Livewire;

use App\Models\Customer;
use App\Services\Stripe\StripeClient;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;

/**
 * Was der Kunde noch schuldet, und der Knopf, es zu begleichen.
 *
 * Die Liste kommt bei jedem Rendern frisch von Stripe. Eine zwischengelagerte
 * Kopie zeigte einen Bezahlknopf neben einer Rechnung, die inzwischen beglichen
 * ist — und der zweite Klick wäre eine zweite Abbuchung.
 */
class OpenInvoices extends Component
{
    /**
     * Was Stripe zur letzten Zahlung gesagt hat, wenn sie nicht durchging.
     *
     * Stripes eigener Wortlaut, nicht eine eigene Umschreibung: er nennt den
     * Grund — abgelaufen, abgelehnt, Deckung — und danach kann der Kunde
     * handeln. „Zahlung fehlgeschlagen" könnte er nur weiterreichen.
     */
    public ?string $failure = null;

    public function pay(string $invoiceId): void
    {
        $stripe = app(StripeClient::class);
        $customerId = $this->stripeCustomerId();

        // Die ID kommt aus dem Browser. Nur was in DIESER Liste steht, darf
        // eingezogen werden — sonst reicht jemand eine fremde Rechnungs-ID ein
        // und Stripe bucht sie von der Karte eines fremden Kunden ab.
        $offen = array_column($stripe->openInvoices($customerId), 'id');
        abort_unless(in_array($invoiceId, $offen, true), 403);

        $ergebnis = $stripe->payInvoice($invoiceId);
        $this->failure = $ergebnis['paid'] ? null : $ergebnis['failure'];

        if ($ergebnis['paid']) {
            $this->dispatch('notify', message: __('billing.invoice_paid'));
        }
    }

    public function payAll(): void
    {
        foreach (app(StripeClient::class)->openInvoices($this->stripeCustomerId()) as $rechnung) {
            $this->pay($rechnung['id']);

            // Nach der ersten Ablehnung anhalten. Alle weiteren scheitern an
            // derselben Karte, und drei Ablehnungen hintereinander lassen
            // Stripes Betrugserkennung anschlagen — danach lehnt sie auch die
            // Karte ab, die in Ordnung wäre.
            if ($this->failure !== null) {
                return;
            }
        }
    }

    private function stripeCustomerId(): string
    {
        $customer = Customer::forUser(Auth::user());

        abort_if($customer === null || blank($customer->stripe_customer_id), 404);

        return (string) $customer->stripe_customer_id;
    }

    public function render()
    {
        return view('livewire.open-invoices', [
            'invoices' => app(StripeClient::class)->openInvoices($this->stripeCustomerId()),
        ]);
    }
}
