<?php

use App\Exceptions\StripeNotConfigured;
use App\Livewire\Billing;
use App\Models\Customer;
use App\Models\Operator;
use App\Models\Order;
use App\Models\User;
use App\Services\Secrets\SecretVault;
use App\Services\Stripe\HttpStripeClient;
use App\Support\OperatingMode;
use Illuminate\Support\Facades\Http;
use Livewire\Livewire;

/**
 * Fehlt der Schlüssel des aktiven Modus, entsteht kein Auftrag — und der Kunde
 * liest einen Satz statt einer 500er-Seite.
 *
 * Die Ausnahme ist eine KONKRETE Klasse. `toThrow(Throwable::class)` würde hier
 * jeden beliebigen Fehler durchgehen lassen, auch einen Tippfehler im Test.
 */
it('refuses to reach stripe without a key for the active mode', function () {
    OperatingMode::set(OperatingMode::Test);

    expect(fn () => app(HttpStripeClient::class)->createPrice('prod_x', 100, 'EUR', 'month'))
        ->toThrow(StripeNotConfigured::class);
});

/**
 * Die andere Hälfte derselben Entscheidung, und der Riegel vor dem Merge:
 * `secret()` WIRFT, `isConfigured()` WIRFT NICHT.
 *
 * Sechs Aufrufer stellen genau diese Frage, um KEINE Ausnahme zu bekommen —
 * CheckoutController:87 (der Kunde liest sonst eine 500 statt eines Satzes),
 * SyncStripeCatalogue, RepriceStripeSubscriptions, SyncStripeAddonItems,
 * MoveStripeSubscriptionPrice. `main` trägt an dieser Stelle noch
 * `return filled($this->secret());`, und der Trockenlauf des Merges führt die
 * Datei OHNE Konfliktmarkierung zusammen: niemand wird gezwungen hinzusehen.
 * Mit `main`s Rumpf und dem werfenden `secret()` dieses Zweigs wird aus der
 * Frage eine Ausnahme — und ohne diesen Test bleiben dabei 1795 Tests grün
 * (nachgewiesen im Schluss-Review durch genau diese Mutation).
 */
it('answers the configured question instead of throwing it', function () {
    Http::fake();
    OperatingMode::set(OperatingMode::Test);

    // Nicht toBeFalse() allein: eine geworfene Ausnahme wäre kein „false",
    // sondern gar keine Antwort — und genau das ist der Rückschritt.
    expect(app(HttpStripeClient::class)->isConfigured())->toBeFalse();

    // Die Frage darf auch nichts kosten: sie wird auf jedem Kassenaufruf
    // gestellt und liest nur den Tresor.
    Http::assertNothingSent();
});

it('says configured once the slot of the active mode is filled', function () {
    Http::fake();
    OperatingMode::set(OperatingMode::Test);
    app(SecretVault::class)->put('stripe.secret', 'sk_test_x', Operator::factory()->create(), OperatingMode::Test);

    expect(app(HttpStripeClient::class)->isConfigured())->toBeTrue();

    Http::assertNothingSent();
});

it('does not create an order when the key is missing', function () {
    OperatingMode::set(OperatingMode::Test);
    $customer = Customer::factory()->create();
    // A portal user is matched to its customer by email, not by a foreign
    // key — see the existing Billing feature tests (e.g. StorageAllowanceTest).
    $user = User::factory()->create(['email' => $customer->email]);

    // 'team' is a real, sellable plan (seeded by the plan-catalogue migration)
    // that ranks above the customer's implicit 'start' plan — a genuine
    // upgrade the purchase() guards would otherwise accept. A made-up key
    // would be refused by the existing plan-validity check regardless of
    // whether the Stripe guard works at all, and would prove nothing.
    //
    // assertHasErrors(), not assertHasNoErrors(): the guard reports through
    // addError('purchase', …) — the same page-blocking pattern order.blade.php
    // already uses for "cannot proceed" — and Livewire's test harness folds
    // any non-empty error bag into the call's result. Asserting no errors
    // here would contradict the very behaviour this test exists to prove.
    Livewire::actingAs($user)
        ->test(Billing::class)
        ->call('purchase', 'upgrade', 'team')
        ->assertHasErrors('purchase');

    // Der Punkt: nach der Zahlung wäre es zu spät. Es darf gar nichts entstehen.
    expect(Order::count())->toBe(0);
});

it('says why instead of failing silently', function () {
    OperatingMode::set(OperatingMode::Test);
    $customer = Customer::factory()->create();
    $user = User::factory()->create(['email' => $customer->email]);

    Livewire::actingAs($user)
        ->test(Billing::class)
        ->call('purchase', 'upgrade', 'team')
        ->assertSee(__('billing.stripe_not_configured'));
});
