<?php

namespace App\Filament\Resources;

use App\Filament\Exports\CustomOrderExporter;
use App\Filament\Resources\Concerns\HasModulePermissions;
use App\Filament\Resources\Concerns\HasStandardTableFeatures;
use App\Filament\Resources\CustomOrderResource\Pages\ListCustomOrders;
use App\Filament\Resources\SalesOrderResource\Pages\ViewSalesOrder;
use App\Filament\Support\Perm;
use App\Filament\Support\StatusLookup;
use App\Models\Lookups\Status;
use App\Models\Sales\SalesOrder;
use App\Models\Sales\SalesOrderItem;
use App\Services\AppSettings;
use App\Services\CurrentContext;
use App\Support\Quantity;
use Filament\Actions\Action;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;

/**
 * The made-to-order work queue.
 *
 * Custom items are always entered on a sales order — that is where the customer
 * and the deadline live, and there is no separate "create a custom order" flow
 * to keep in step. This listing is the other view of the same rows: every
 * custom line across every order, flattened so whoever is actually making the
 * things can work a single list instead of opening orders one by one.
 *
 * Read-only by design. Editing a line means editing the order it belongs to,
 * so the row links straight there rather than offering a second, divergent
 * place to change the same data.
 */
class CustomOrderResource extends Resource
{
    use HasModulePermissions;
    use HasStandardTableFeatures;

    protected static ?string $model = SalesOrderItem::class;

    protected static string $permissionModuleKey = 'isms_custom_orders';

    protected static string $exporter = CustomOrderExporter::class;

    protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedSparkles;

    protected static string|\UnitEnum|null $navigationGroup = 'Sales';

    protected static ?string $navigationLabel = 'Custom Orders';

    protected static ?int $navigationSort = 20;

    protected static ?string $slug = 'custom-orders';

    protected static ?string $modelLabel = 'custom order';

    protected static ?string $recordTitleAttribute = 'product_name';

    public static function canCreate(): bool
    {
        return false;
    }

    public static function canEdit(Model $record): bool
    {
        return false;
    }

    public static function canDelete(Model $record): bool
    {
        return false;
    }

    public static function canDeleteAny(): bool
    {
        return false;
    }

    public static function canView(Model $record): bool
    {
        return false;
    }

    /**
     * Mirrors the sales-order listing's own scoping: without `view_all` a user
     * only sees custom work from orders they took themselves.
     */
    public static function canViewAll(): bool
    {
        return Auth::user()?->hasPermissionTo('isms_custom_orders.view_all') ?? false;
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->where('is_custom', true)
            // A line whose order was deleted, cancelled or already invoiced is
            // not work anybody still has to do — but it stays reachable through
            // the filters below rather than vanishing outright.
            ->whereHas('salesOrder');
    }

    public static function table(Table $table): Table
    {
        $warningDays = app(AppSettings::class)->salesOrderDeadlineWarningDays();

        return static::standardTableDefaults($table)
            ->recordUrl(static::standardRecordUrl())
            ->emptyStateHeading('No custom orders yet')
            ->emptyStateDescription('Made-to-order lines will appear here once taken.')
            ->modifyQueryUsing(fn (Builder $query): Builder => $query
                ->with(['salesOrder.customer', 'salesOrder.status', 'salesOrder.branch'])
                ->when(
                    ! static::canViewAll(),
                    fn (Builder $q) => $q->whereHas('salesOrder', fn ($qq) => $qq->where('created_by', Auth::id())),
                ))
            ->columns([
                TextColumn::make('salesOrder.order_number')
                    ->label('Order #')
                    ->badge()
                    ->searchable()
                    ->sortable(),
                TextColumn::make('product_name')
                    ->label('Item')
                    ->searchable()
                    ->wrap()
                    ->weight('medium')
                    ->description(fn (SalesOrderItem $record): ?string => $record->custom_description),
                TextColumn::make('custom_specification')
                    ->label('Exact details')
                    ->wrap()
                    ->lineClamp(3)
                    ->placeholder('—')
                    ->searchable()
                    ->toggleable(),
                TextColumn::make('salesOrder.customer.business_name')
                    ->label('Customer')
                    ->placeholder('—')
                    ->searchable()
                    ->description(fn (SalesOrderItem $record): ?string => $record->salesOrder?->customer?->phone),
                TextColumn::make('salesOrder.branch.name')->label('Branch')->placeholder('—')->toggleable(),
                TextColumn::make('quantity')
                    ->sortable()
                    ->formatStateUsing(fn ($state, SalesOrderItem $record): string => Quantity::format($state, $record->unit)),
                TextColumn::make('unit_price')->label('Unit price')->money(fn () => app(CurrentContext::class)->currencyCode()),
                TextColumn::make('line_total')->label('Line total')->money(fn () => app(CurrentContext::class)->currencyCode())->sortable(),
                TextColumn::make('salesOrder.status.name')
                    ->label('Order status')
                    ->badge()
                    ->color(fn (SalesOrderItem $record): string => StatusLookup::colorOf(
                        Status::CTX_SALES_ORDER,
                        $record->salesOrder?->status?->code ?? '',
                    )),
                TextColumn::make('salesOrder.deadline_date')
                    ->label('Deadline')
                    ->date()
                    ->sortable()
                    ->placeholder('—')
                    ->badge()
                    ->color(fn (SalesOrderItem $record): string => $record->salesOrder
                        ? SalesOrderResource::deadlineColor($record->salesOrder, $warningDays)
                        : 'gray')
                    ->description(fn (SalesOrderItem $record): ?string => $record->salesOrder
                        ? SalesOrderResource::deadlineNote($record->salesOrder)
                        : null),
                TextColumn::make('salesOrder.order_date')->label('Ordered')->date()->sortable()->toggleable(),
            ])
            // Soonest deadline first — this is a work queue, so the thing due
            // next belongs at the top. Undated items coalesce to a far-future
            // date so they sort last rather than leading the list (both MySQL
            // and sqlite otherwise put NULLs first on an ascending sort).
            ->defaultSort(fn (Builder $query): Builder => $query->orderBy(
                SalesOrder::query()
                    ->selectRaw("coalesce(deadline_date, '9999-12-31')")
                    ->whereColumn('sales_orders.id', 'sales_order_items.sales_order_id'),
            ))
            ->filters([
                SelectFilter::make('order_status')
                    ->label('Order status')
                    ->options(fn (): array => StatusLookup::options(Status::CTX_SALES_ORDER))
                    ->query(fn (Builder $query, array $data): Builder => $query->when(
                        $data['value'] ?? null,
                        fn (Builder $q, $code) => $q->whereHas(
                            'salesOrder.status',
                            fn ($qq) => $qq->where('code', $code),
                        ),
                    )),
                Filter::make('outstanding')
                    ->label('Still to make')
                    ->toggle()
                    ->default()
                    ->query(fn (Builder $query): Builder => $query->whereHas(
                        'salesOrder',
                        fn (Builder $q) => $q->open(),
                    )),
                Filter::make('due_soon')
                    ->label('Due soon or overdue')
                    ->toggle()
                    ->query(fn (Builder $query): Builder => $query->whereHas(
                        'salesOrder',
                        fn (Builder $q) => $q
                            ->open()
                            ->whereNotNull('deadline_date')
                            ->whereDate('deadline_date', '<=', now()->addDays($warningDays)->toDateString()),
                    )),
                Filter::make('customer')
                    ->schema([TextInput::make('value')->label('Customer name or phone')])
                    ->query(fn (Builder $query, array $data): Builder => $query->when(
                        $data['value'] ?? null,
                        fn (Builder $q, $value) => $q->whereHas('salesOrder.customer', fn ($qq) => $qq
                            ->where('business_name', 'like', "%{$value}%")
                            ->orWhere('phone', 'like', "%{$value}%")),
                    )),
                Filter::make('deadline_date')
                    ->schema([
                        DatePicker::make('deadline_from')->label('Deadline from'),
                        DatePicker::make('deadline_to')->label('Deadline to'),
                    ])
                    ->query(fn (Builder $query, array $data): Builder => $query
                        ->when($data['deadline_from'] ?? null, fn (Builder $q, $d) => $q->whereHas(
                            'salesOrder',
                            fn ($qq) => $qq->whereDate('deadline_date', '>=', $d),
                        ))
                        ->when($data['deadline_to'] ?? null, fn (Builder $q, $d) => $q->whereHas(
                            'salesOrder',
                            fn ($qq) => $qq->whereDate('deadline_date', '<=', $d),
                        ))),
            ])
            ->filtersLayout(FiltersLayout::AboveContentCollapsible)
            ->filtersFormColumns(2)
            ->headerActions(static::standardExportActions())
            ->toolbarActions(static::standardExportBulkActions())
            ->recordActions([
                Action::make('openOrder')
                    ->label('Open order')
                    ->icon(Heroicon::OutlinedArrowTopRightOnSquare)
                    ->url(fn (SalesOrderItem $record): ?string => $record->salesOrder
                        ? ViewSalesOrder::getUrl(['record' => $record->sales_order_id])
                        : null)
                    ->visible(fn (SalesOrderItem $record): bool => $record->salesOrder !== null
                        && Perm::can('isms_sales_orders', 'view')),
            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => ListCustomOrders::route('/'),
        ];
    }
}
