<?php

use App\Livewire\CustomerProvisioning;
use App\Models\Customer;
use App\Models\Datacenter;
use App\Models\Host;
use App\Models\Order;
use App\Models\ProvisioningRun;
use App\Models\User;
use App\Provisioning\Steps\Customer\ReserveResources;
use Livewire\Livewire;

/**
 * The same promise, before the money and after it.
 *
 * A visitor reading "wird sofort ausgeliefert" on the price sheet must not find
 * a different sentence on the page they land on once they have paid — and where
 * a machine has to be bought first, both pages have to say so rather than one
 * of them promising and the other apologising.
 */
beforeEach(function () {
    Datacenter::factory()->create(['code' => 'fsn1']);
});

it('promises immediate delivery on the price sheet only where a host has room', function () {
    // Room for the small package, nowhere near enough for the big one: Start
    // braucht 40 GB, Business 200.
    Host::factory()->active()->create(['datacenter' => 'fsn1', 'total_gb' => 150, 'reserve_pct' => 0]);

    $response = $this->get('/');

    $response->assertOk()
        ->assertSee(__('delivery.immediate'))
        ->assertSee(__('delivery.scheduled'));
});

it('promises nothing immediate before a single machine has been onboarded', function () {
    // A fresh installation sells nothing on the spot. Saying otherwise is a
    // promise the very first customer catches us breaking.
    Host::query()->delete();

    $this->get('/')
        ->assertOk()
        ->assertSee(__('delivery.scheduled'))
        ->assertDontSee(__('delivery.immediate'));
});

it('tells a waiting customer their cloud is being prepared, not that it broke', function () {
    // Parked is not failed and not slow. Left under the generic "wird
    // eingerichtet" wording, a customer watching a stepper stand still for two
    // days has every reason to think something went wrong.
    $user = User::factory()->create();
    $customer = Customer::factory()->create(['email' => $user->email]);
    $order = Order::factory()->withSubscription()->create([
        'customer_id' => $customer->id,
        'plan' => 'start',
        'datacenter' => 'fsn1',
        'status' => 'paid',
    ]);

    $pipeline = (array) config('provisioning.pipelines.customer');

    ProvisioningRun::factory()->create([
        'subject_type' => Order::class,
        'subject_id' => $order->id,
        'pipeline' => 'customer',
        'current_step' => array_search(ReserveResources::class, $pipeline, true),
        'status' => ProvisioningRun::STATUS_WAITING,
    ]);

    Livewire::actingAs($user)
        ->test(CustomerProvisioning::class)
        ->assertViewHas('parked', true)
        ->assertSee(__('delivery.parked_title'))
        ->assertDontSee(__('dashboard.provisioning_failed'));
});

it('does not call an ordinary step in flight a delivery delay', function () {
    // Only the reservation step means "waiting for a machine". Every other
    // wait is provisioning doing its job.
    $user = User::factory()->create();
    $customer = Customer::factory()->create(['email' => $user->email]);
    $order = Order::factory()->withSubscription()->create([
        'customer_id' => $customer->id,
        'plan' => 'start',
        'datacenter' => 'fsn1',
        'status' => 'paid',
    ]);

    ProvisioningRun::factory()->create([
        'subject_type' => Order::class,
        'subject_id' => $order->id,
        'pipeline' => 'customer',
        'current_step' => 5,
        'status' => ProvisioningRun::STATUS_WAITING,
    ]);

    Livewire::actingAs($user)
        ->test(CustomerProvisioning::class)
        ->assertViewHas('parked', false)
        ->assertDontSee(__('delivery.parked_title'));
});
