<?php

namespace App\Filament\Widgets;

use App\Filament\Resources\SalesOrderResource;
use App\Filament\Resources\SalesOrderResource\Pages\ListSalesOrders;
use App\Filament\Support\Kpi;
use App\Models\Sales\SalesOrder;
use App\Services\AppSettings;
use Filament\Widgets\Concerns\InteractsWithPageTable;
use Filament\Widgets\StatsOverviewWidget;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;

/**
 * The order desk's four numbers, over the same ownership-scoped query the
 * listing uses.
 *
 * "Due soon" replaces the old "total pending" figure: on a board of orders with
 * deadlines, what people need at a glance is how much work is about to come
 * due, not a running total of unpaid balances (which the balance column already
 * gives per row).
 *
 * On the list page the widget is wired through HasKpiHeader, so the figures
 * react to the active table filters and the status tab; on the dashboard (no
 * table props passed) it falls back to the base scoped query.
 */
class SalesOrderTotalsOverview extends StatsOverviewWidget
{
    use InteractsWithPageTable;

    protected static ?int $sort = 5;

    protected int|string|array $columnSpan = 'full';

    /**
     * Order-desk money, so `isms_sales_orders.access` is required alongside the
     * dashboard gate — see InvoiceTotalsOverview for the same reasoning.
     */
    public static function canView(): bool
    {
        return (Auth::user()?->hasPermissionTo('dashboard.access') ?? false)
            && SalesOrderResource::canViewAny();
    }

    protected function getTablePage(): string
    {
        return ListSalesOrders::class;
    }

    protected function getStats(): array
    {
        $warningDays = app(AppSettings::class)->salesOrderDeadlineWarningDays();

        $query = $this->tableFilters !== null
            ? $this->getPageTableQuery()
            : SalesOrderResource::getEloquentQuery();

        $scoped = fn (): Builder => $query->clone()
            ->when(! SalesOrderResource::canViewAll(), fn (Builder $q) => $q->where('created_by', Auth::id()));

        $open = $scoped()->open();
        $dueSoon = $scoped()
            ->open()
            ->whereNotNull('deadline_date')
            ->whereDate('deadline_date', '<=', now()->addDays($warningDays)->toDateString())
            ->count();
        $overdue = $scoped()
            ->open()
            ->whereNotNull('deadline_date')
            ->whereDate('deadline_date', '<', now()->toDateString())
            ->count();

        return [
            Kpi::count('Open orders', $open->count())
                ->icon('heroicon-m-shopping-cart')
                ->toStat(),
            Kpi::money('Open value', (float) $scoped()->open()->sum('net_total'))
                ->icon('heroicon-m-currency-dollar')
                ->toStat(),
            Kpi::money('Advances held', (float) $scoped()->open()->sum('advance_paid'))
                ->icon('heroicon-m-banknotes')
                ->description('Paid before invoicing')
                ->toStat(),
            Kpi::count('Due soon', $dueSoon)
                ->icon('heroicon-m-exclamation-triangle')
                ->description($overdue > 0 ? "{$overdue} already overdue" : "Within {$warningDays} day(s)")
                ->alertWhen(fn (): bool => $overdue > 0)
                ->toStat(),
        ];
    }
}
