<?php

use App\Livewire\Dashboard;
use App\Models\Customer;
use App\Models\Instance;
use App\Models\InstanceMetric;
use App\Models\User;
use Illuminate\Support\Carbon;
use Livewire\Livewire;

/**
 * The measurements behind the panel's ring and trend.
 *
 * The rule they all serve: a reading that could not be taken is not a reading
 * of zero. Charting a failed sample as 0 GB tells a customer their data is
 * gone, and charting a missing day as no traffic draws an outage that never
 * happened.
 */

function metricFor(Instance $instance, string $day, ?int $used, ?int $total, int $rx = 0, int $tx = 0): InstanceMetric
{
    return InstanceMetric::create([
        'instance_id' => $instance->id,
        'day' => $day,
        'disk_used_bytes' => $used,
        'disk_total_bytes' => $total,
        'rx_bytes' => $rx,
        'tx_bytes' => $tx,
    ]);
}

function customerWithInstance(): array
{
    $user = User::factory()->create();
    $customer = Customer::factory()->create(['user_id' => $user->id]);
    $instance = Instance::factory()->create(['customer_id' => $customer->id, 'status' => 'active', 'quota_gb' => 500]);

    return [$user, $instance];
}

it('shows the allowance, not a ring, until something has been measured', function () {
    [$user, $instance] = customerWithInstance();

    Livewire::actingAs($user)
        ->test(Dashboard::class)
        ->assertViewHas('disk', null)
        // The contractual figure is true and says so; a ring at 0 % would read
        // as "your cloud is empty".
        ->assertSee(__('dashboard.master.storage_note'));
});

it('draws the ring once a reading exists', function () {
    [$user, $instance] = customerWithInstance();

    metricFor($instance, Carbon::today()->toDateString(), used: 235_000_000_000, total: 500_000_000_000);

    Livewire::actingAs($user)
        ->test(Dashboard::class)
        ->assertViewHas('disk', fn (?array $d) => $d !== null && (int) round($d['percent']) === 47);
});

it('keeps the last good reading when a sample could not be taken', function () {
    [$user, $instance] = customerWithInstance();

    metricFor($instance, Carbon::yesterday()->toDateString(), used: 200_000_000_000, total: 500_000_000_000);
    // Today's row exists — the traffic half of the sampler wrote it — but the
    // guest agent did not answer, so the disk columns stayed null.
    metricFor($instance, Carbon::today()->toDateString(), used: null, total: null, rx: 5_000);

    Livewire::actingAs($user)
        ->test(Dashboard::class)
        ->assertViewHas('disk', fn (?array $d) => $d !== null && $d['used'] === 200_000_000_000);
});

it('passes the measured days to the trend, and only those', function () {
    [$user, $instance] = customerWithInstance();

    metricFor($instance, Carbon::today()->subDays(2)->toDateString(), null, null, rx: 1_000, tx: 500);
    metricFor($instance, Carbon::today()->subDay()->toDateString(), null, null, rx: 2_000, tx: 500);
    metricFor($instance, Carbon::today()->toDateString(), null, null, rx: 4_000, tx: 1_000);
    // Outside the window the panel draws.
    metricFor($instance, Carbon::today()->subDays(40)->toDateString(), null, null, rx: 9_999_999);

    Livewire::actingAs($user)
        ->test(Dashboard::class)
        ->assertViewHas('trend', [1_500, 2_500, 5_000]);
});
