<?php

declare(strict_types=1);

namespace App\Filament\Widgets;

use App\Enums\BookingStatus;
use App\Models\Booking;
use App\Models\PackagePurchase;
use Carbon\CarbonImmutable;
use Filament\Widgets\StatsOverviewWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;

/**
 * The admin's day in four numbers.
 *
 * Chosen so that a glance answers "is there anything I have to do?". Three of
 * the four are counts of work owed; the fourth exists to show the work that
 * did not need doing, which is the measure of whether steering customers
 * toward payment links is paying off.
 */
class StudioOverview extends StatsOverviewWidget
{
    protected ?string $pollingInterval = '60s';

    // Rendered inline rather than deferred. Each lazy widget costs an extra
    // round trip, and the target host caps concurrent PHP processes in the
    // low twenties — four cheap aggregate queries are better spent inline.
    protected static bool $isLazy = false;

    protected function getStats(): array
    {
        $now = CarbonImmutable::now('UTC');
        [$dayStart, $dayEnd] = self::todayWindow();

        $awaiting = Booking::query()
            ->live($now)
            ->whereIn('status', BookingStatus::needingAttention())
            ->count();

        $todayConfirmed = Booking::query()
            ->whereBetween('starts_at', [$dayStart, $dayEnd])
            ->whereIn('status', [BookingStatus::Confirmed->value, BookingStatus::Completed->value])
            ->count();

        $unassigned = Booking::query()
            ->where('staff_required', '>', 0)
            ->whereNull('assigned_engineer_id')
            ->where('starts_at', '>=', $now)
            ->where('status', BookingStatus::Confirmed->value)
            ->count();

        $expiringPackages = PackagePurchase::query()
            ->where('status', 'active')
            ->where('studio_slots_remaining', '>', 0)
            ->whereBetween('expires_at', [$now, $now->addDays(7)])
            ->count();

        return [
            Stat::make('Needs a decision', (string) $awaiting)
                ->description($awaiting === 0
                    ? 'Nothing waiting on you'
                    : 'Payments to verify against the statement')
                ->descriptionIcon($awaiting === 0 ? 'heroicon-m-check-circle' : 'heroicon-m-exclamation-circle')
                ->color($awaiting === 0 ? 'success' : 'warning'),

            Stat::make('Sessions today', (string) $todayConfirmed)
                ->description(self::todayLabel())
                ->descriptionIcon('heroicon-m-calendar')
                ->color('primary'),

            Stat::make('Without an engineer', (string) $unassigned)
                ->description($unassigned === 0
                    ? 'Every session is staffed'
                    : 'Confirmed sessions still needing someone')
                ->descriptionIcon('heroicon-m-user-minus')
                ->color($unassigned === 0 ? 'success' : 'warning'),

            Stat::make('Packages expiring', (string) $expiringPackages)
                ->description($expiringPackages === 0
                    ? 'None running out this week'
                    : 'Have unused hours and under 7 days left')
                ->descriptionIcon('heroicon-m-clock')
                ->color($expiringPackages === 0 ? 'gray' : 'warning'),
        ];
    }

    /** @return array{0: CarbonImmutable, 1: CarbonImmutable} */
    private static function todayWindow(): array
    {
        $start = CarbonImmutable::now(config('studio.timezone'))->startOfDay();

        return [$start->setTimezone('UTC'), $start->addDay()->setTimezone('UTC')];
    }

    private static function todayLabel(): string
    {
        return CarbonImmutable::now(config('studio.timezone'))->format('l j F');
    }
}
