<?php

use App\Livewire\Admin\Customers;
use App\Livewire\Admin\GrantPlan;
use App\Models\Customer;
use App\Models\PlanFamily;
use App\Models\Subscription;
use App\Models\SubscriptionAddon;
use App\Provisioning\Jobs\AdvanceRunJob;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

/**
 * The console's side of granting: a modal (R20) on the customer's own row,
 * gated by its own capability rather than merely hidden (mutation target #3).
 *
 * 'fsn' is seeded by the datacenters migration itself (baseline data, like
 * the mailbox seeding) — no factory needed for it here.
 */
it('refuses to open for an operator without the capability, not merely hides the button', function () {
    $customer = Customer::factory()->create();

    // Support has customers.manage (can suspend, impersonate) but never had
    // customers.grant_plan — giving away service is a bigger deal than a
    // reversible suspend, and the seed migration deliberately keeps this one
    // to Owner. A capability check that only hid the button would still let
    // this request through.
    Livewire::actingAs(operator('Support'), 'operator')
        ->test(GrantPlan::class, ['uuid' => $customer->uuid])
        ->assertForbidden();
});

it('hides the grant button from an operator without the capability', function () {
    Customer::factory()->create();

    Livewire::actingAs(operator('Support'), 'operator')
        ->test(Customers::class)
        ->assertDontSee(__('admin.grant_action'));
});

it('shows the grant button to the Owner', function () {
    Customer::factory()->create();

    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(Customers::class)
        ->assertSee(__('admin.grant_action'));
});

it('grants a free package to a customer with no contract yet', function () {
    Queue::fake();
    $customer = Customer::factory()->create();
    $owner = operator('Owner');

    Livewire::actingAs($owner, 'operator')
        ->test(GrantPlan::class, ['uuid' => $customer->uuid])
        ->set('plan', 'team')
        ->set('term', 'monthly')
        ->set('datacenter', 'fsn')
        ->set('priceEuros', '0')
        ->set('note', 'Testkunde')
        ->call('grant')
        ->assertHasNoErrors();

    $subscription = Subscription::query()->where('customer_id', $customer->id)->sole();

    expect($subscription->price_cents)->toBe(0)
        ->and($subscription->isGranted())->toBeTrue()
        ->and($subscription->granted_by)->toBe($owner->id);

    Queue::assertPushed(AdvanceRunJob::class);
});

it('still lets an internal package be granted — that is the one door it has', function () {
    // Ein internes Paket verlässt sellable() und damit Preisblatt, Bestellung
    // und Warenkorb (Aufgabe 6). Dieses Formular liest bewusst grantable()
    // statt sellable() für sein Dropdown UND seine Validierung — sonst wäre
    // das interne Paket auch hier draußen und nirgends mehr vergebbar.
    // Die Familie bringt die Migration mit, seit die neue Leiter das
    // Testpaket in den Katalog einer frischen Installation räumt.
    expect(PlanFamily::query()->where('key', 'test')->value('internal'))->toBeTruthy();

    $customer = Customer::factory()->create();

    Livewire::actingAs(operator('Owner'), 'operator')
        ->test(GrantPlan::class, ['uuid' => $customer->uuid])
        ->set('plan', 'test')
        ->set('term', 'monthly')
        ->set('datacenter', 'fsn')
        ->set('priceEuros', '0')
        ->call('grant')
        ->assertHasNoErrors();

    expect(Subscription::query()->where('customer_id', $customer->id)->sole()->plan)->toBe('test');
});

it('grants a discounted module onto an existing contract', function () {
    $customer = Customer::factory()->create();
    Subscription::factory()->create(['customer_id' => $customer->id, 'status' => 'active']);
    $owner = operator('Owner');

    Livewire::actingAs($owner, 'operator')
        ->test(GrantPlan::class, ['uuid' => $customer->uuid])
        ->assertSet('kind', 'addon') // a contract already exists — default to the module form
        ->set('addonKey', 'priority_support')
        ->set('quantity', 1)
        ->set('priceEuros', '5,00')
        ->call('grant')
        ->assertHasNoErrors();

    $addon = SubscriptionAddon::query()->where('addon_key', 'priority_support')->sole();

    expect($addon->price_cents)->toBe(500)
        ->and($addon->isGranted())->toBeTrue()
        ->and($addon->granted_by)->toBe($owner->id);
});

it('shows who granted what, when, and until when', function () {
    $customer = Customer::factory()->create();
    $owner = operator('Owner');
    $until = now()->addMonths(3);

    Subscription::factory()->create([
        'customer_id' => $customer->id, 'status' => 'active',
        'price_cents' => 0, 'granted_by' => $owner->id, 'granted_at' => now(),
        'grant_note' => 'Sponsoring', 'granted_until' => $until, 'catalogue_price_cents' => 17900,
    ]);

    Livewire::actingAs($owner, 'operator')
        ->test(GrantPlan::class, ['uuid' => $customer->uuid])
        ->assertSee($owner->name)
        ->assertSee('Sponsoring')
        ->assertSee($until->local()->isoFormat('D. MMM YYYY'));
});
