<?php

namespace Modules\Booking\Filament\Resources\Bookings\Tables;

use Filament\Actions\ViewAction;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Toggle;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Modules\Booking\Enums\BookingStatus;
use Modules\Booking\Filament\Resources\Bookings\Actions\AssignDriverTableAction;
use Modules\Booking\Filament\Resources\Bookings\Actions\CancelBookingTableAction;
use Modules\Booking\Filament\Resources\Bookings\Actions\DeleteBookingTableAction;
use Modules\Booking\Filament\Resources\Bookings\Actions\RestoreBookingTableAction;
use Modules\Booking\Filament\Resources\Bookings\Actions\SetRemarkTableAction;
use Modules\Booking\Models\Booking;
use Modules\Catalog\Models\EvCompany;
use Modules\Payment\Filament\Actions\RefundBookingTableAction;
use Modules\Routing\Models\EvRoute;

class BookingsTable
{
    public static function configure(Table $table): Table
    {
        return $table
            ->modifyQueryUsing(fn (Builder $query) => $query
                // A round trip's return leg is its own Booking row, but
                // showing both legs side by side in one list reads as two
                // unrelated bookings rather than one round trip — hide it
                // here; it's still reachable via the primary leg's "Linked
                // Leg" link on the detail page (view its own row directly).
                ->where('is_return_leg', false)
                ->with([
                    'route.company', 'route.fromDestination', 'route.toDestination', 'timeSlot', 'vehicleOptions',
                    'linkedBooking',
                ]))
            ->defaultSort('created_at', 'desc')
            ->columns([
                TextColumn::make('booking_ref')
                    ->label('Ref')
                    ->searchable()
                    ->sortable(),
                TextColumn::make('status')
                    ->badge()
                    ->color(fn (BookingStatus $state) => match ($state) {
                        BookingStatus::PendingPayment => 'warning',
                        BookingStatus::Confirmed => 'success',
                        BookingStatus::Cancelled => 'gray',
                        BookingStatus::Expired => 'danger',
                    }),
                TextColumn::make('route.company.name')
                    ->label('Company')
                    ->searchable()
                    ->sortable(),
                TextColumn::make('route.fromDestination.name')
                    ->label('From'),
                TextColumn::make('route.toDestination.name')
                    ->label('To'),
                TextColumn::make('travel_date')
                    ->date()
                    ->sortable(),
                TextColumn::make('timeSlot.label')
                    ->label('Time Slot'),
                IconColumn::make('is_round_trip')
                    ->label('Round Trip')
                    ->boolean()
                    ->toggleable(),
                TextColumn::make('vehicleOptions')
                    ->label('Vehicle Options')
                    ->state(fn (Booking $record) => $record->vehicleOptions
                        ->map(fn ($line) => str($line->vehicle_option->value)->headline().' x'.$line->passenger_count)
                        ->all())
                    ->listWithLineBreaks(),
                TextColumn::make('price')
                    ->label('Price')
                    // Since the return leg no longer has its own row (it's
                    // now hidden — see the query above), the price shown
                    // here for a round trip needs to be both legs combined,
                    // or it silently reads as just the outbound half.
                    ->state(fn (Booking $record) => $record->is_round_trip
                        ? bcadd((string) $record->price, (string) ($record->linkedBooking?->price ?? '0'), 2)
                        : $record->price)
                    ->description(fn (Booking $record) => $record->is_round_trip
                        ? number_format((float) $record->price, 2).' + '.number_format((float) ($record->linkedBooking?->price ?? 0), 2)
                        : null)
                    ->numeric(2)
                    ->sortable(),
                TextColumn::make('passenger_name')
                    ->label('Passenger')
                    ->description(fn (Booking $record) => $record->passenger_phone)
                    ->searchable(['passenger_name', 'passenger_phone'])
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('created_by_channel')
                    ->badge()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('driver_name')
                    ->label('Driver')
                    ->placeholder('Not yet assigned')
                    ->description(fn (Booking $record) => collect([$record->driver_phone, $record->car_plate_number, $record->car_model])
                        ->filter()
                        ->join(' • ') ?: null)
                    ->searchable(['driver_name', 'driver_phone', 'car_plate_number', 'car_model'])
                    ->toggleable(),
                TextColumn::make('notes')
                    ->label('Customer Notes')
                    ->placeholder('—')
                    ->limit(50)
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('remark')
                    ->label('Staff Remark')
                    ->placeholder('—')
                    ->limit(50)
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('created_at')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                SelectFilter::make('status')
                    ->options(array_combine(
                        array_map(fn (BookingStatus $status) => $status->value, BookingStatus::cases()),
                        array_map(fn (BookingStatus $status) => str($status->value)->headline()->toString(), BookingStatus::cases()),
                    )),
                Filter::make('travel_date')
                    ->schema([
                        DatePicker::make('travel_date'),
                    ])
                    ->query(fn (Builder $query, array $data) => $query->when(
                        $data['travel_date'] ?? null,
                        fn (Builder $q, $date) => $q->whereDate('travel_date', $date),
                    )),
                SelectFilter::make('ev_route_id')
                    ->label('Route')
                    ->options(fn () => EvRoute::with(['fromDestination', 'toDestination'])->get()
                        ->mapWithKeys(fn (EvRoute $route) => [
                            $route->id => "{$route->fromDestination?->name} → {$route->toDestination?->name}",
                        ]))
                    ->searchable(),
                SelectFilter::make('company')
                    ->options(fn () => EvCompany::pluck('name', 'id'))
                    ->searchable()
                    ->query(fn (Builder $query, array $data) => $query->when(
                        $data['value'] ?? null,
                        fn (Builder $q, $companyId) => $q->whereHas('route', fn (Builder $rq) => $rq->where('ev_company_id', $companyId)),
                    )),
                // is_round_trip is a computed accessor (linked_booking_id
                // !== null), not a DB column — TernaryFilter builds a raw
                // where() on it, which breaks now that the column is gone.
                Filter::make('is_round_trip')
                    ->schema([Toggle::make('is_round_trip')])
                    ->query(fn (Builder $query, array $data) => $query->when(
                        $data['is_round_trip'] ?? null,
                        fn (Builder $q) => $q->whereNotNull('linked_booking_id'),
                    )),
                // Deleted bookings are soft-deleted, not hard-removed
                // (domain.md; T7.x follow-up) — this is the only place they
                // become visible again, off by default.
                TrashedFilter::make(),
            ])
            ->recordActions([
                ViewAction::make(),
                AssignDriverTableAction::make(),
                SetRemarkTableAction::make(),
                CancelBookingTableAction::make(),
                RefundBookingTableAction::make(),
                DeleteBookingTableAction::make(),
                RestoreBookingTableAction::make(),
            ]);
    }
}
