<?php

use App\Models\Host;
use App\Models\Instance;
use App\Models\Order;
use App\Models\ProvisioningRun;
use App\Models\SubscriptionAddon;
use App\Provisioning\Steps\Customer\ResizeVirtualMachine;
use App\Services\Billing\AddonCatalogue;

/**
 * Was ein Block auf der Platte bedeutet.
 *
 * Der Kopfraum wächst mit der Instanz (max(10 GB, 12 %)), sonst gilt die Regel
 * nur für frisch gekaufte Pakete und nicht für gestapelte. Eine volle Platte
 * legt nicht den Upload still, sondern die Instanz.
 *
 * Absichtlich KEIN Test, der die Formel aus `growDisk()` isoliert nachrechnet:
 * so eine Fassung wäre grün geblieben, selbst wenn der Schritt eine andere,
 * falsche Formel benutzt hätte — und eine erste Fassung dieser Datei ist genau
 * daran gescheitert (die nachgerechnete Zeile hatte kein `max(0, …)` um den
 * neuen Summanden, der echte Code in `ResizeVirtualMachine.php` hat eins). Der
 * einzige Test hier fährt den Schritt selbst und liest ab, was er tatsächlich
 * tut.
 */

/**
 * Ein frisch reservierter 'start'-Lauf: 30 GB Kontingent, 40 GB Platte
 * (`database/migrations/2026_08_01_000004_switch_to_new_plan_ladder.php`),
 * kein Block gebucht.
 *
 * Absichtlich eine eigene, in sich geschlossene Hilfsfunktion statt
 * `reservedRun()` aus `CustomerStepsTest.php` zu teilen: diese Datei muss auch
 * ALLEIN laufen (`… test tests/Feature/Provisioning/StoragePackHeadroomTest.php`),
 * nicht nur im Verbund mit einer Nachbardatei, die zufällig zuerst geladen
 * wurde. Jede andere Datei in diesem Verzeichnis bringt ihre Hilfsfunktionen
 * ebenso selbst mit (`hostRun()`, `restartableInstance()`,
 * `paidOrderWithSubscription()`) — geteilt wird nur, was in `tests/Pest.php`
 * steht, das Pest immer lädt.
 */
function packHeadroomRun(): array
{
    $host = Host::factory()->active()->create(['datacenter' => 'fsn', 'node' => 'pve']);
    $order = Order::factory()->withSubscription()->create(['datacenter' => 'fsn', 'plan' => 'start']);
    // Größe aus dem Vertrag, nicht aus den Vorgaben der Fabrik: so schreibt sie
    // ReserveResources, und die Vorgaben der Fabrik beschreiben noch das alte
    // Startpaket (100 GB auf 120). Ein Lauf, der von dort ausginge, prüfte den
    // Kopfraum eines Pakets, das es nicht mehr gibt.
    $instance = Instance::factory()->create([
        'order_id' => $order->id, 'customer_id' => $order->customer_id,
        'host_id' => $host->id, 'vmid' => 101, 'status' => 'provisioning',
        'quota_gb' => $order->subscription->quota_gb,
        'disk_gb' => $order->subscription->disk_gb,
    ]);
    $run = ProvisioningRun::factory()->create([
        'subject_type' => Order::class, 'subject_id' => $order->id, 'pipeline' => 'customer',
        'context' => [
            'instance_id' => $instance->id, 'host_id' => $host->id, 'node' => 'pve',
            'vmid' => 101, 'subdomain' => $instance->subdomain, 'plan' => 'start',
        ],
    ]);

    return compact('host', 'order', 'instance', 'run');
}

// Drei Blöcke à 20 GB nutzbar / 22 GB belegt kommen direkt als
// SubscriptionAddon-Zeile dazu, statt über BookAddon zu buchen — das würde
// einen Lieferlauf anstoßen und Stripe befragen, was hier nichts zur Sache
// tut; gefragt ist nur, was ResizeVirtualMachine aus einer bereits gebuchten
// Zeile macht.
//
// Ziel: 30 (Kontingent) + 60 (drei Blöcke à 20) + 10 (Kopfraum des Pakets,
// 40-30) + 6 (Kopfraum der Blöcke, 66-60 belegt) = 106 GB.
it('vergrößert die Platte um Paket- und Block-Kopfraum, und nur einmal', function () {
    $s = fakeServices();
    ['run' => $run, 'instance' => $instance, 'order' => $order] = packHeadroomRun();

    SubscriptionAddon::create([
        'subscription_id' => $order->subscription->id,
        'addon_key' => AddonCatalogue::STORAGE,
        'price_cents' => 1000,
        'currency' => 'EUR',
        'quantity' => 3,
        'booked_at' => now(),
        'pack_gb' => 20,
        'pack_disk_gb' => 22,
    ]);

    expect(app(ResizeVirtualMachine::class)->execute($run)->type)->toBe('advance')
        ->and($s['pve']->resizeCalls)->toContain('101:scsi0:106G')
        ->and($instance->fresh()->disk_gb)->toBe(106);

    // Wiederholungslauf: das Ziel ist absolut, nicht '+…', also darf ein
    // zweiter Durchlauf nicht noch einmal vergrößern.
    $s['pve']->resizeCalls = [];
    expect(app(ResizeVirtualMachine::class)->execute($run->fresh())->type)->toBe('advance')
        ->and($s['pve']->resizeCalls)->toBe([])
        ->and($instance->fresh()->disk_gb)->toBe(106);
});
