<?php

declare(strict_types=1);

namespace App\Filament\Resources;

use App\Enums\JobStatus;
use App\Filament\Resources\JobResource\Pages;
use App\Models\Deposit;
use App\Models\Flow;
use App\Models\Job;
use App\Models\Vehicle;
use Carbon\Carbon;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Filament\Infolists\Components\Section as InfoSection;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Infolist;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\Summarizers\Summarizer;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Facades\Schema;

class JobResource extends Resource
{
    protected static ?string $model = Job::class;

    protected static ?string $navigationIcon  = 'heroicon-o-clipboard-document-check';
    protected static ?string $navigationLabel = 'Jobs';
    protected static ?string $navigationGroup = 'Operations';
    protected static ?int    $navigationSort  = 1;

    // -------------------------------------------------------------------------
    // FORM
    // -------------------------------------------------------------------------

    public static function form(Form $form): Form
    {
        return $form
            ->columns(12)
            ->schema([
                Tabs::make('Job')
                    ->columnSpanFull()
                    ->tabs([
                        // ============== Flow & Status ============
                        Tabs\Tab::make('Flow & Status')
                            ->columnSpanFull()
                            ->schema([
                                Grid::make(12)
                                    ->columnSpanFull()
                                    ->schema([
                                        Select::make('flow_id')
                                            ->label('Flow')
                                            ->helperText('Pick the template of rules this Job should follow. The Hold value will prefill from this Flow.')
                                            ->relationship('flow', 'name')
                                            ->searchable()
                                            ->preload(false)
                                            ->getSearchResultsUsing(
                                                function (string $query) {
                                                    return Flow::query()
                                                        ->where('name', 'like', "%{$query}%")
                                                        ->limit(25)
                                                        ->pluck('name', 'id');
                                                }
                                            )
                                            ->getOptionLabelUsing(
                                                fn (?string $value): ?string => $value
                                                    ? Flow::find($value)?->name
                                                    : null
                                            )
                                            ->reactive()
                                            ->afterStateUpdated(
                                                function (?string $state, Set $set): void {
                                                    $cents = (int) (Flow::find($state)?->hold_amount_cents ?? 0);
                                                    $set('hold_from_flow_display', number_format($cents / 100, 2, '.', ''));
                                                }
                                            )
                                            ->required()
                                            ->columnSpan(6),

                                        Select::make('status')
                                            ->label('Status')
                                            ->helperText('Lifecycle of this Job (e.g. pending → active → captured/released).')
                                            ->options(
                                                collect(JobStatus::cases())->mapWithKeys(
                                                    fn ($c) => [$c->value => $c->value]
                                                )->all()
                                            )
                                            ->required()
                                            ->columnSpan(6),

                                        TextInput::make('external_reference')
                                            ->label('Booking reference')
                                            ->helperText('Your booking number/reference used outside this system.')
                                            ->maxLength(120)
                                            ->columnSpan(6),

                                        Select::make('vehicle_id')
                                            ->label('Vehicle')
                                            ->helperText('Pick the Vehicle record this Job relates to. Auto-filled from VEVS where possible.')
                                            ->relationship('vehicle', 'name')
                                            ->searchable()
                                            ->preload()
                                            ->getSearchResultsUsing(
                                                function (string $search) {
                                                    return Vehicle::query()
                                                        ->where(function ($query) use ($search) {
                                                            $query->where('name', 'like', "%{$search}%")
                                                                ->orWhere('registration', 'like', "%{$search}%");
                                                        })
                                                        ->limit(50)
                                                        ->get()
                                                        ->pluck('display_name', 'id');
                                                }
                                            )
                                            ->getOptionLabelUsing(
                                                fn (?string $value): ?string => $value
                                                    ? Vehicle::find($value)?->display_name
                                                    : null
                                            )
                                            ->nullable()
                                            ->columnSpan(6),

                                        TextInput::make('vevs_car_id')
                                            ->label('VEVS car ID')
                                            ->helperText('Internal reference to the VEVS car_id from the reservation feed.')
                                            ->maxLength(120)
                                            ->columnSpan(6),

                                        TextInput::make('source_system')
                                            ->label('Source system')
                                            ->helperText('Where this booking originated (e.g. vevs, website, manual).')
                                            ->maxLength(50)
                                            ->columnSpan(6),
                                    ]),
                            ]),

                        // ============== Agreement ============
                        Tabs\Tab::make('Agreement')
                            ->columnSpanFull()
                            ->schema([
                                Section::make('Agreement')
                                    ->description('Upload the signed rental agreement (PDF).')
                                    ->schema([
                                        FileUpload::make('agreement_path')
                                            ->label('Rental agreement (PDF)')
                                            ->disk('agreements')
                                            ->directory('job-agreements')
                                            ->visibility('private')
                                            ->acceptedFileTypes(['application/pdf'])
                                            ->maxSize(10 * 1024)
                                            ->preserveFilenames()
                                            ->helperText('PDF only, max 10MB.'),
                                    ])
                                    ->columnSpanFull(),
                            ])
                            ->lazy(),

                        // ============== Customer ============
                        Tabs\Tab::make('Customer')
                            ->columnSpanFull()
                            ->schema([
                                Section::make('Customer')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            TextInput::make('customer_name')
                                                ->label('Customer name')
                                                ->helperText('Primary contact for this booking.')
                                                ->columnSpan(6),

                                            TextInput::make('customer_email')
                                                ->label('Email')
                                                ->helperText('Used for receipts and notifications.')
                                                ->email()
                                                ->columnSpan(6),

                                            TextInput::make('customer_phone')
                                                ->label('Phone')
                                                ->helperText('Optional, for urgent contact if required.')
                                                ->columnSpan(6),
                                        ]),
                                    ])
                                    ->columnSpanFull(),

                                Section::make('Drivers & travel')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            TextInput::make('primary_driver_licence')
                                                ->label('Primary driver licence')
                                                ->columnSpan(4),

                                            TextInput::make('primary_driver_dob')
                                                ->label('Primary driver DOB')
                                                ->placeholder('YYYY-MM-DD')
                                                ->columnSpan(4),

                                            TextInput::make('secondary_driver_name')
                                                ->label('Secondary driver name')
                                                ->columnSpan(4),

                                            TextInput::make('secondary_driver_licence')
                                                ->label('Secondary driver licence')
                                                ->columnSpan(4),

                                            TextInput::make('secondary_driver_dob')
                                                ->label('Secondary driver DOB')
                                                ->placeholder('YYYY-MM-DD')
                                                ->columnSpan(4),

                                            TextInput::make('flight_number')
                                                ->label('Flight number')
                                                ->columnSpan(4),

                                            TextInput::make('airline')
                                                ->label('Airline')
                                                ->columnSpan(4),

                                            TextInput::make('customer_notes')
                                                ->label('Customer notes')
                                                ->columnSpan(12)
                                                ->extraAttributes(['style' => 'min-height: 4rem;']),
                                        ]),
                                    ])
                                    ->columnSpanFull(),

                                Section::make('Billing address')
                                    ->description('Stored as structured JSON on this Job.')
                                    ->schema([
                                        Group::make()
                                            ->statePath('billing_address')
                                            ->schema([
                                                Grid::make(12)->schema([
                                                    TextInput::make('line1')
                                                        ->label('Address line 1')
                                                        ->columnSpan(12),

                                                    TextInput::make('line2')
                                                        ->label('Address line 2')
                                                        ->columnSpan(12),

                                                    TextInput::make('city')
                                                        ->label('City')
                                                        ->columnSpan(4),

                                                    TextInput::make('region')
                                                        ->label('Region/State')
                                                        ->columnSpan(4),

                                                    TextInput::make('postcode')
                                                        ->label('Postcode')
                                                        ->columnSpan(4),

                                                    TextInput::make('country')
                                                        ->label('Country')
                                                        ->default('New Zealand')
                                                        ->columnSpan(4),
                                                ]),
                                            ])
                                            ->columnSpanFull(),
                                    ])
                                    ->columnSpanFull(),
                            ])
                            ->lazy(),

                        // ============== Booking details ============
                        Tabs\Tab::make('Booking details')
                            ->columnSpanFull()
                            ->schema([
                                Section::make('Rental & locations')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            TextInput::make('rental_days')
                                                ->label('Rental days')
                                                ->numeric()
                                                ->columnSpan(3),

                                            TextInput::make('rental_hours')
                                                ->label('Rental hours')
                                                ->numeric()
                                                ->columnSpan(3),

                                            TextInput::make('pickup_location_id')
                                                ->label('Pickup location ID')
                                                ->helperText('Imported from VEVS; will map to Locations later.')
                                                ->numeric()
                                                ->columnSpan(3),

                                            TextInput::make('return_location_id')
                                                ->label('Return location ID')
                                                ->helperText('Imported from VEVS; will map to Locations later.')
                                                ->numeric()
                                                ->columnSpan(3),
                                        ]),
                                    ])
                                    ->columnSpanFull(),
                            ])
                            ->lazy(),

                        // ============== Dates ============
                        Tabs\Tab::make('Dates')
                            ->columnSpanFull()
                            ->schema([
                                Section::make('Dates')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            DateTimePicker::make('start_at')
                                                ->label('Start')
                                                ->seconds(false)
                                                ->native(false)
                                                ->required()
                                                ->helperText('Local time.')
                                                ->columnSpan(6),

                                            DateTimePicker::make('end_at')
                                                ->label('End')
                                                ->seconds(false)
                                                ->native(false)
                                                ->required()
                                                ->minDate(fn (Get $get) => $get('start_at') ?: null)
                                                ->rule('after_or_equal:start_at')
                                                ->helperText('Must be after Start.')
                                                ->columnSpan(6),
                                        ]),
                                    ])
                                    ->columnSpanFull(),
                            ])
                            ->lazy(),

                        // ============== Financials ============
                        Tabs\Tab::make('Financials')
                            ->columnSpanFull()
                            ->schema([
                                Section::make('Financials')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            TextInput::make('charge_amount_cents')
                                                ->label('Charge (NZD)')
                                                ->prefix('NZ$')
                                                ->numeric()
                                                ->required()
                                                ->formatStateUsing(
                                                    fn ($state) => $state !== null
                                                        ? number_format(((int) $state) / 100, 2, '.', '')
                                                        : null
                                                )
                                                ->dehydrateStateUsing(
                                                    function ($state) {
                                                        if ($state === null || $state === '') {
                                                            return null;
                                                        }

                                                        return (int) round(((float) $state) * 100);
                                                    }
                                                )
                                                ->helperText('Stored as cents; shown as dollars.')
                                                ->columnSpan(4),

                                            TextInput::make('hold_from_flow_display')
                                                ->label('Hold (NZD) — from Flow')
                                                ->disabled()
                                                ->dehydrated(false)
                                                ->afterStateHydrated(
                                                    function (TextInput $component, $state, ?Job $record): void {
                                                        $cents = (int) (
                                                            $record?->hold_amount_cents_from_flow
                                                            ?? $record?->flow?->hold_amount_cents
                                                            ?? 0
                                                        );

                                                        $component->state(
                                                            number_format($cents / 100, 2, '.', '')
                                                        );
                                                    }
                                                )
                                                ->columnSpan(4),

                                            Placeholder::make('paid_amount')
                                                ->label('Paid to date')
                                                ->content(
                                                    fn (?Job $record) => $record?->paidAmountFormatted() ?? '—'
                                                )
                                                ->dehydrated(false)
                                                ->columnSpan(2),

                                            Placeholder::make('remaining_amount')
                                                ->label('Remaining')
                                                ->content(
                                                    fn (?Job $record) => $record?->owingAmountFormatted() ?? '—'
                                                )
                                                ->dehydrated(false)
                                                ->columnSpan(2),
                                        ]),
                                    ])
                                    ->columnSpanFull(),

                                // EXTRA MILEAGE – passed through to EditJob::afterSave()
                                Section::make('Extra mileage')
                                    ->description('Any additional mileage charges for this booking. The owner receives 100% of this charge.')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            TextInput::make('extra_mileage_amount')
                                                ->label('Extra mileage charge (NZD)')
                                                ->prefix('NZ$')
                                                ->numeric()
                                                ->minValue(0)
                                                ->placeholder('Leave blank if none')
                                                ->helperText('When you save, this will create/update an owner ledger entry for extra mileage with 100% paid to the owner.')
                                                ->dehydrated(false) // handled in EditJob::afterSave
                                                ->columnSpan(4),
                                        ]),
                                    ])
                                    ->columnSpanFull(),
                            ])
                            ->lazy(),

                        // ============== VEVS pricing ============
                        Tabs\Tab::make('VEVS pricing')
                            ->columnSpanFull()
                            ->schema([
                                Section::make('VEVS pricing snapshot')
                                    ->description('Read-only mirror of the original VEVS booking values.')
                                    ->schema([
                                        Grid::make(12)->schema([
                                            // … existing VEVS inputs (unchanged) …
                                        ]),
                                    ])
                                    ->columnSpanFull(),
                            ])
                            ->lazy(),

                        // ============== Metadata ============
                        Tabs\Tab::make('Metadata (Admin only)')
                            ->columnSpanFull()
                            ->schema([
                                // … existing Metadata section (unchanged) …
                            ])
                            ->lazy(),

                        // ============== Deposit ============
                        Tabs\Tab::make('Deposit')
                            ->columnSpanFull()
                            ->schema([
                                Grid::make(12)->schema([
                                    TextInput::make('deposit_amount')
                                        ->label('Deposit received (NZD)')
                                        ->prefix('NZ$')
                                        ->numeric()
                                        ->minValue(0)
                                        ->placeholder('Leave blank if none')
                                        ->dehydrated(false)   // IMPORTANT: not stored on jobs table
                                        ->columnSpan(4),
                                ]),
                            ]),
                    ])
                    ->persistTabInQueryString(),
            ]);
    }

    // -------------------------------------------------------------------------
    // INFOLIST
    // -------------------------------------------------------------------------

    public static function infolist(Infolist $infolist): Infolist
    {
        return $infolist->schema([
            InfoSection::make('Summary')
                ->schema([
                    TextEntry::make('external_reference')
                        ->label('Job reference')
                        ->copyable(),

                    TextEntry::make('booking_reference')
                        ->label('External reference')
                        ->copyable()
                        ->visible(fn (Job $record) => filled($record->booking_reference)),

                    TextEntry::make('flow.name')
                        ->label('Flow'),

                    TextEntry::make('status')
                        ->label('Status'),

                    TextEntry::make('vehicle.name')
                        ->label('Vehicle'),

                    TextEntry::make('source_system')
                        ->label('Source system'),

                    TextEntry::make('customer_name')
                        ->label('Customer'),

                    TextEntry::make('customer_email')
                        ->label('Email'),

                    TextEntry::make('customer_phone')
                        ->label('Phone'),

                    TextEntry::make('start_at')
                        ->label('Start at')
                        ->dateTime('D d M, H:i'),

                    TextEntry::make('end_at')
                        ->label('End at')
                        ->dateTime('D d M, H:i'),
                ])
                ->columns(3),

            InfoSection::make('Customer')
                ->schema([
                    TextEntry::make('customer_name')->label('Name'),
                    TextEntry::make('customer_email')->label('Email'),
                    TextEntry::make('customer_phone')->label('Phone'),
                    TextEntry::make('customer_notes')->label('Notes'),
                ])
                ->columns(2),

            InfoSection::make('Dates')
                ->schema([
                    TextEntry::make('start_at')
                        ->label('Start at')
                        ->dateTime('D d M Y, H:i'),

                    TextEntry::make('end_at')
                        ->label('End at')
                        ->dateTime('D d M Y, H:i'),

                    TextEntry::make('created_at')
                        ->label('Created at')
                        ->dateTime('D d M Y, H:i'),

                    TextEntry::make('updated_at')
                        ->label('Last updated')
                        ->dateTime('D d M Y, H:i'),
                ])
                ->columns(4),

            InfoSection::make('Financials')
                ->schema([
                    TextEntry::make('charge_amount_cents')
                        ->label('Charge (NZD)')
                        ->getStateUsing(
                            fn ($state) => 'NZ$ ' . number_format(((int) ($state ?? 0)) / 100, 2)
                        ),

                    TextEntry::make('hold_from_flow')
                        ->label('Hold (NZD) — from Flow')
                        ->getStateUsing(
                            fn (Job $record) => 'NZ$ ' . number_format(
                                ((int) (optional($record->flow)->hold_amount_cents ?? 0)) / 100,
                                2
                            )
                        ),

                    TextEntry::make('paid_amount_cents')
                        ->label('Paid to date')
                        ->getStateUsing(
                            fn (Job $record, $state) =>
                                $record->paidAmountFormatted()
                                ?? 'NZ$ ' . number_format(((int) ($state ?? 0)) / 100, 2)
                        ),

                    TextEntry::make('remaining_amount_cents')
                        ->label('Remaining')
                        ->getStateUsing(
                            fn (Job $record, $state) =>
                                $record->owingAmountFormatted()
                                ?? 'NZ$ ' . number_format(((int) ($state ?? 0)) / 100, 2)
                        ),

                    // Optional read-only extra mileage display if you later add jobs.extra_mileage_cents
                    TextEntry::make('extra_mileage_cents')
                        ->label('Extra mileage (NZD)')
                        ->visible(fn () => Schema::hasColumn('jobs', 'extra_mileage_cents'))
                        ->getStateUsing(function (Job $record) {
                            $cents = (int) ($record->extra_mileage_cents ?? 0);

                            if ($cents <= 0) {
                                return '—';
                            }

                            return 'NZ$ ' . number_format($cents / 100, 2);
                        }),
                ])
                ->columns(4),

            InfoSection::make('Hold status')
                ->schema([
                    TextEntry::make('hold_status_text')
                        ->label('Status')
                        ->getStateUsing(fn (Job $record) => static::holdStateText($record)),

                    TextEntry::make('hold_amount_display')
                        ->label('Hold amount')
                        ->getStateUsing(function (Job $record) {
                            $dep = static::latestDepositForJob($record);
                            if (! $dep) {
                                return '—';
                            }

                            $cents = (int) ($dep->amount_cents ?? 0);

                            return $cents > 0
                                ? 'NZ$ ' . number_format($cents / 100, 2)
                                : '—';
                        }),

                    TextEntry::make('hold_captured_at')
                        ->label('Captured at')
                        ->getStateUsing(function (Job $record) {
                            $dep = static::latestDepositForJob($record);
                            $ts  = $dep?->captured_at;

                            if (! $ts) {
                                return '—';
                            }

                            return $ts instanceof \Carbon\CarbonInterface
                                ? $ts->format('Y-m-d H:i')
                                : Carbon::parse($ts)->format('Y-m-d H:i');
                        }),

                    TextEntry::make('hold_planned_cancel_at')
                        ->label('Planned auto-cancel')
                        ->getStateUsing(function (Job $record) {
                            $dep = static::latestDepositForJob($record);
                            $p   = $dep?->planned_cancel_at;

                            if (! $p) {
                                return '—';
                            }

                            return $p instanceof \Carbon\CarbonInterface
                                ? $p->format('Y-m-d H:i')
                                : Carbon::parse($p)->format('Y-m-d H:i');
                        }),
                ])
                ->columns(4),
        ]);
    }

    // -------------------------------------------------------------------------
    // TABLE
    // -------------------------------------------------------------------------

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                IconColumn::make('is_paid_in_full')
                    ->label('Payment')
                    ->tooltip(
                        fn (Job $record) => $record->is_paid_in_full
                            ? 'Paid in full'
                            : 'Balance owing'
                    )
                    ->boolean()
                    ->trueIcon('heroicon-m-check-circle')
                    ->falseIcon('heroicon-m-exclamation-triangle')
                    ->trueColor('success')
                    ->falseColor('warning'),

                TextColumn::make('external_reference')
                    ->label('Job')
                    ->sortable()
                    ->searchable()
                    ->formatStateUsing(function (?string $state, Job $record): string {
                        if (isset($record->display_ref)) {
                            return (string) $record->display_ref;
                        }

                        if (! empty($state)) {
                            return $state;
                        }

                        return 'Job #' . $record->id;
                    }),

                TextColumn::make('status')
                    ->label('Status')
                    ->badge()
                    ->sortable(),

                TextColumn::make('start_at')
                    ->label('Pickup')
                    ->sortable()
                    ->toggleable()
                    ->getStateUsing(function (Job $record): string {
                        if (! $record->start_at) {
                            return '—';
                        }

                        $start = $record->start_at instanceof Carbon
                            ? $record->start_at
                            : Carbon::parse($record->start_at);

                        $datePart = $start->format('D d M, H:i');

                        $today     = now()->startOfDay();
                        $pickupDay = (clone $start)->startOfDay();
                        $diff      = $today->diffInDays($pickupDay, false);

                        if ($diff === 0) {
                            $relative = 'Today';
                        } elseif ($diff === 1) {
                            $relative = 'Tomorrow';
                        } elseif ($diff > 1) {
                            $relative = 'In ' . $diff . ' days';
                        } elseif ($diff === -1) {
                            $relative = 'Yesterday';
                        } else {
                            $relative = abs($diff) . ' days ago';
                        }

                        return $datePart . ' (' . $relative . ')';
                    }),

                TextColumn::make('customer_name')
                    ->label('Customer')
                    ->searchable(),

                TextColumn::make('vehicle.name')
                    ->label('Vehicle')
                    ->sortable()
                    ->searchable()
                    ->toggleable(),

                TextColumn::make('charge_amount_cents')
                    ->label('Charge (NZD)')
                    ->alignRight()
                    ->sortable()
                    ->formatStateUsing(
                        fn ($state) => number_format(((int) ($state ?? 0)) / 100, 2)
                    ),

                TextColumn::make('paid_display')
                    ->label('Paid (NZD)')
                    ->alignRight()
                    ->getStateUsing(
                        fn (Job $record) => $record->paidAmountFormatted()
                    ),

                TextColumn::make('owing_display')
                    ->label('Owing (NZD)')
                    ->alignRight()
                    ->getStateUsing(
                        fn (Job $record) => $record->owingAmountFormatted()
                    )
                    ->summarize([
                        Summarizer::make()
                            ->label('Total unpaid')
                            ->using(
                                function ($query): string {
                                    $expr = '(COALESCE(charge_amount_cents,0) - COALESCE((
                                        SELECT COALESCE(SUM(amount_cents),0)
                                        FROM payments
                                        WHERE payments.job_id = jobs.id
                                          AND status IN ("succeeded","captured")
                                    ),0))';

                                    if (Schema::hasColumn('jobs', 'remaining_amount_cents')) {
                                        $cents = (int) ((clone $query)
                                            ->where('remaining_amount_cents', '>', 0)
                                            ->sum('remaining_amount_cents') ?? 0);
                                    } else {
                                        $cents = (int) ((clone $query)
                                            ->whereRaw("$expr > 0")
                                            ->selectRaw("SUM($expr) as agg")
                                            ->value('agg') ?? 0);
                                    }

                                    return 'NZ$ ' . number_format($cents / 100, 2);
                                }
                            ),
                    ]),

                TextColumn::make('updated_at')
                    ->since()
                    ->label('Updated')
                    ->sortable(),
            ])
            ->filters([
                Tables\Filters\SelectFilter::make('status')
                    ->label('Status')
                    ->options(
                        collect(JobStatus::cases())->mapWithKeys(
                            fn ($c) => [$c->value => $c->value]
                        )->all()
                    ),

                Tables\Filters\SelectFilter::make('pickup_window')
                    ->label('Pickup window')
                    ->options([
                        'today'   => 'Today',
                        'next_14' => 'Next 14 days',
                        'overdue' => 'Overdue (start in past)',
                        'future'  => 'All future',
                    ])
                    ->default('next_14')
                    ->query(function (EloquentBuilder $query, array $data): EloquentBuilder {
                        if (! isset($data['value']) || ! $data['value']) {
                            return $query;
                        }

                        $today = now()->startOfDay();

                        return match ($data['value']) {
                            'today'   => $query->whereBetween('start_at', [
                                $today,
                                $today->copy()->endOfDay(),
                            ]),
                            'next_14' => $query->whereBetween('start_at', [
                                $today,
                                $today->copy()->addDays(14)->endOfDay(),
                            ]),
                            'overdue' => $query->whereNotNull('start_at')
                                ->where('start_at', '<', $today),
                            'future'  => $query->where('start_at', '>=', $today),
                            default   => $query,
                        };
                    }),

                TernaryFilter::make('is_paid_in_full')
                    ->label('Unpaid only')
                    ->trueLabel('Paid only')
                    ->falseLabel('Unpaid only')
                    ->boolean()
                    ->queries(
                        true: function (EloquentBuilder $q) {
                            if (Schema::hasColumn('jobs', 'remaining_amount_cents')) {
                                return $q->where('remaining_amount_cents', 0)
                                    ->where('charge_amount_cents', '>', 0);
                            }

                            return $q->whereRaw('COALESCE(charge_amount_cents,0) > 0')
                                ->whereRaw('(COALESCE(charge_amount_cents,0) - COALESCE((
                                    SELECT COALESCE(SUM(amount_cents),0)
                                    FROM payments
                                    WHERE payments.job_id = jobs.id
                                      AND status IN ("succeeded","captured")
                                ),0)) = 0');
                        },
                        false: function (EloquentBuilder $q) {
                            if (Schema::hasColumn('jobs', 'remaining_amount_cents')) {
                                return $q->where('remaining_amount_cents', '>', 0);
                            }

                            return $q->whereRaw('(COALESCE(charge_amount_cents,0) - COALESCE((
                                    SELECT COALESCE(SUM(amount_cents),0)
                                    FROM payments
                                    WHERE payments.job_id = jobs.id
                                      AND status IN ("succeeded","captured")
                                ),0)) > 0');
                        },
                        blank: fn (EloquentBuilder $q) => $q,
                    ),
            ])
            ->recordClasses(
                fn (Job $record) => $record->is_paid_in_full
                    ? 'bg-emerald-950/10 hover:bg-emerald-950/20'
                    : 'bg-amber-950/5 hover:bg-amber-950/15'
            )
            ->actions([
                Tables\Actions\ViewAction::make(),
                Tables\Actions\EditAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\DeleteBulkAction::make(),
            ])
            ->defaultSort('start_at', 'asc');
    }

    // -------------------------------------------------------------------------
    // SEARCH / RELATIONS / PAGES
    // -------------------------------------------------------------------------

    public static function getGloballySearchableAttributes(): array
    {
        return [
            'external_reference',
            'customer_name',
            'vehicle.name',
        ];
    }

    public static function getWidgets(): array
    {
        return [
            \App\Filament\Resources\JobResource\Widgets\JobStats::class,
        ];
    }

    public static function getRelations(): array
    {
        return [
            JobResource\RelationManagers\EventsRelationManager::class,
            \App\Filament\Resources\JobResource\RelationManagers\DamagesRelationManager::class,
        ];
    }

    public static function getPages(): array
    {
        return [
            'index'  => Pages\ListJobs::route('/'),
            'create' => Pages\CreateJob::route('/create'),
            'edit'   => Pages\EditJob::route('/{record}/edit'),
            'view'   => Pages\ViewJob::route('/{record}'),
        ];
    }

    // -------------------------------------------------------------------------
    // Helper methods for Hold status (used by infolist)
    // -------------------------------------------------------------------------

    protected static function latestDepositForJob(Job $job): ?Deposit
    {
        return Deposit::query()
            ->where('job_id', $job->getKey())
            ->latest('id')
            ->first();
    }

    protected static function holdState(Job $job): string
    {
        $dep = static::latestDepositForJob($job);

        if (! $dep) {
            $planned = (int) (optional($job->flow)->hold_amount_cents ?? 0);

            return $planned > 0 ? 'not_created' : 'none';
        }

        if (! empty($dep->captured_at)) {
            return 'captured';
        }

        $status = (string) $dep->status;

        if (in_array($status, ['requires_action', 'requires_confirmation'], true)) {
            return 'needs_authorization';
        }

        if (in_array($status, ['requires_capture', 'authorized'], true)) {
            return 'authorized_not_captured';
        }

        if (in_array($status, ['pending', 'processing'], true)) {
            return 'pending';
        }

        return 'none';
    }

    protected static function holdStateText(Job $job): string
    {
        return match (static::holdState($job)) {
            'not_created'             => 'Not created',
            'needs_authorization'     => 'Needs customer authorisation',
            'authorized_not_captured' => 'Authorised — not captured',
            'pending'                 => 'Pending',
            'captured'                => 'Captured',
            default                   => 'No hold',
        };
    }
}
