<?php

declare(strict_types=1);

namespace App\Filament\Resources\Bookings\Schemas;

use App\Models\Booking;
use App\Models\Payment;
use Filament\Infolists\Components\RepeatableEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Support\Enums\FontWeight;
use Filament\Support\Enums\TextSize;

/**
 * Everything the admin needs to settle one booking, on one screen.
 *
 * Built as a read-only view rather than an edit form on purpose: the times and
 * the room cannot be changed here, because doing so would leave booking_slots
 * describing a different reservation from the one on display. Moving a booking
 * goes through the reschedule action, which rewrites both together.
 */
class BookingInfolist
{
    public static function configure(Schema $schema): Schema
    {
        return $schema->components([
            Section::make('Payment')
                ->description('Match this against the Revolut statement, not the screenshot.')
                ->schema([
                    TextEntry::make('reference')
                        ->label('Reference')
                        ->copyable()
                        ->weight(FontWeight::Bold)
                        ->size(TextSize::Large),
                    TextEntry::make('price_total')->label('Expected')->money('GBP'),
                    TextEntry::make('status')->label('Status')->badge(),
                    TextEntry::make('hold_expires_at')
                        ->label('Hold ends')
                        ->dateTime('j M, H:i', config('studio.timezone'))
                        ->placeholder('No hold running'),
                ])
                ->columns(4),

            Section::make('Payments')
                ->description('Every attempt against this booking, including refunds owed.')
                ->schema([
                    RepeatableEntry::make('payments')
                        ->hiddenLabel()
                        ->schema([
                            TextEntry::make('method')->label('Method')->badge(),
                            TextEntry::make('status')->label('Status')->badge(),
                            TextEntry::make('amount')->label('Amount')->money('GBP'),
                            TextEntry::make('external_ref')
                                ->label('Revolut order')
                                ->copyable()
                                ->placeholder('—'),
                            TextEntry::make('paid_at')
                                ->label('Settled')
                                ->dateTime('j M, H:i', config('studio.timezone'))
                                ->placeholder('Not yet'),
                            TextEntry::make('needs_manual_refund')
                                ->label('Action needed')
                                // The money arrived after the slot was gone.
                                // A customer is out of pocket and does not
                                // know it, so this cannot be subtle.
                                ->state(fn (Payment $record) => $record->needs_manual_refund
                                    ? 'Refund owed — paid after the slot was lost'
                                    : null)
                                ->badge()
                                ->color('danger')
                                ->placeholder('—'),
                        ])
                        ->columns(3),
                ])
                ->visible(fn (Booking $record) => $record->payments()->exists()),

            Section::make('Session')
                ->schema([
                    TextEntry::make('room.name')->label('Room'),
                    TextEntry::make('type')->label('Kind')->badge(),
                    TextEntry::make('starts_at')
                        ->label('Starts')
                        ->dateTime('D j M Y, H:i', config('studio.timezone')),
                    TextEntry::make('ends_at')
                        ->label('Ends')
                        ->dateTime('H:i', config('studio.timezone')),
                    TextEntry::make('session_type')->label('Session type')->badge()->placeholder('—'),
                    TextEntry::make('staff_required')
                        ->label('Staff needed')
                        ->formatStateUsing(fn (int $state) => match ($state) {
                            0 => 'None — self-serve',
                            1 => '1 engineer',
                            default => "{$state} people",
                        }),
                    TextEntry::make('assignedEngineer.name')->label('Assigned')->placeholder('Unassigned'),
                    TextEntry::make('preferredEngineer.name')->label('Artist asked for')->placeholder('No preference'),
                ])
                ->columns(4),

            Section::make('Artist')
                ->schema([
                    TextEntry::make('user.profile.artist_name')->label('Artist name')->placeholder('—'),
                    TextEntry::make('user.email')->label('Email')->copyable(),
                    TextEntry::make('user.profile.phone')->label('Phone')->copyable()->placeholder('—'),
                    TextEntry::make('user.profile.completed_bookings_count')
                        ->label('Sessions completed')
                        ->badge()
                        ->color('gray'),
                ])
                ->columns(4),

            Section::make('Package')
                ->visible(fn (Booking $record) => $record->isPaidByPackage())
                ->schema([
                    TextEntry::make('packagePurchase.package.name')->label('Package'),
                    TextEntry::make('studio_slots_used')
                        ->label('Studio time used')
                        ->formatStateUsing(fn (int $state) => self::hours($state)),
                    TextEntry::make('engineer_slots_used')
                        ->label('Engineer time used')
                        ->formatStateUsing(fn (int $state) => self::hours($state)),
                    TextEntry::make('packagePurchase.expires_at')
                        ->label('Package expires')
                        ->date('j M Y'),
                ])
                ->columns(4),

            Section::make('Birthday')
                ->visible(fn (Booking $record) => $record->guest_count !== null)
                ->schema([
                    TextEntry::make('guest_count')
                        ->label('Guests')
                        ->formatStateUsing(fn (?int $state) => $state.' of 10'),
                    TextEntry::make('responsible_adult_name')
                        ->label('Responsible adult')
                        ->placeholder('Not recorded')
                        // Ages 10+ means minors on site, so this is a
                        // safeguarding field, not an optional nicety.
                        ->color(fn (?string $state) => $state === null ? 'warning' : null),
                ])
                ->columns(4),

            Section::make('Notes')
                ->collapsed()
                ->schema([
                    TextEntry::make('cancellation_reason')->label('Cancellation reason')->placeholder('—'),
                    TextEntry::make('refund_due')->label('Refund recorded')->money('GBP')->placeholder('—'),
                    TextEntry::make('reschedule_count')->label('Times moved'),
                    TextEntry::make('created_at')->label('Booked')->dateTime('j M Y, H:i', config('studio.timezone')),
                ])
                ->columns(4),
        ]);
    }

    private static function hours(int $slots): string
    {
        $hours = $slots * (int) config('studio.slot_minutes') / 60;

        return rtrim(rtrim(number_format($hours, 1), '0'), '.').' hours';
    }
}
