<?php

namespace App\Filament\Resources\BookingUserResource\Pages;

use App\Filament\Resources\BookingUserResource;
use App\Models\Booking;
use App\Models\Computer;
use App\Models\Enum\ComputerStatusEnum;
use App\Models\Enum\UserSessionStatusEnum;
use App\Models\Side;
use App\Models\UserSession;
use Carbon\Carbon;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Validation\ValidationException;

class CreateBookingUser extends CreateRecord
{
    protected static string $resource = BookingUserResource::class;

    protected function mutateFormDataBeforeCreate(array $data): array
    {
        $data["user_id"] = auth()->user()->id;

        $activeSession = UserSession::query()
            ->where('user_id', auth()->user()->id)
            ->where('is_active', true)
            ->exists();

        if ($activeSession) {
            \Filament\Notifications\Notification::make()
                ->title('Creation Booking Error')
                ->body('His user already has an active session and cannot book another reservation.')
                ->danger()
                ->send();
            throw ValidationException::withMessages([]);
        }

        $computersAvailable = Computer::query()
            ->where('side_id', $data['side_id'])
            ->where('reserved', false)
            ->where('computer_status_id', ComputerStatusEnum::ID[ComputerStatusEnum::ACTIVE])
            ->whereDoesntHave('bookings', function ($query) use ($data) {
                $query->where(function ($subQuery) use ($data) {
                    $subQuery->whereBetween('start_time', [$data['start_time'], $data['end_time']])
                        ->orWhereBetween('end_time', [$data['start_time'], $data['end_time']])
                        ->orWhere(function ($overlapQuery) use ($data) {
                            $overlapQuery->where('start_time', '<=', $data['start_time'])
                                ->where('end_time', '>=', $data['end_time']);
                        });
                });
            })
            ->exists();

        if (!$computersAvailable) {
            \Filament\Notifications\Notification::make()
                ->title('Creation Booking Error')
                ->body('No available computers for the selected time range.')
                ->danger()
                ->send();
            throw ValidationException::withMessages([]);
        }

        $side  = Side::find($data['side_id']);

        $currentDate = Carbon::now();
        $season = $this->isWinterSeason($currentDate, $side->winter_start_date) ? "winter" : "summer";
        $startTime = Carbon::parse($data['start_time']);
        $endTime = Carbon::parse($data['end_time']);
        $dayOfWeek = $startTime->format('l');
        $seasonHours = $season === 'winter' ? $side->operating_hours_winter : $side->operating_hours_summer;
        $operatingHours = $this->getOperatingHours($dayOfWeek, $seasonHours);

        if (!$operatingHours) {
            \Filament\Notifications\Notification::make()
                ->title('Creation Booking Error')
                ->body('No operating hours for this day.')
                ->danger()
                ->send();
            throw ValidationException::withMessages([]);
        }

        $openTime = Carbon::parse($operatingHours['open'])->format('H:i:s');
        $closeTime = Carbon::parse($operatingHours['close'])->format('H:i:s');

        $startTimeFormatted = $startTime->format('H:i:s');
        $endTimeFormatted = $endTime->format('H:i:s');

        if ($startTimeFormatted < $openTime || $startTimeFormatted > $closeTime) {
            \Filament\Notifications\Notification::make()
                ->title('Creation Booking Error')
                ->body('The booking start time must be within operating hours.')
                ->danger()
                ->send();
            throw ValidationException::withMessages([]);
        }

        if ($endTimeFormatted > $closeTime) {
            \Filament\Notifications\Notification::make()
                ->title('Creation Booking Error')
                ->body('The booking end time must be within operating hours.')
                ->danger()
                ->send();
            throw ValidationException::withMessages([]);
        }

        $durationInMinutes = $startTime->diffInMinutes($endTime);
        if ($durationInMinutes < 1) {
            \Filament\Notifications\Notification::make()
                ->title('Creation Booking Error')
                ->body('Reservations must be at least 1 minute')
                ->danger()
                ->send();
            throw ValidationException::withMessages([]);
        }

        $data["date"] = $data['start_time'];

        $data["creator_user"] = auth()->user()->id;

        return $data;
    }

    protected function afterCreate(): void
    {
        /** @var Booking $booking */
        $booking = $this->record;

        $startTime = Carbon::parse($booking->start_time);
        $endTime = Carbon::parse($booking->end_time);
        $duration = $startTime->diffInMinutes($endTime);

        UserSession::create([
            'side_id' => $booking->side_id,
            'computer_id' => $booking->computer_id,
            'start_time' => $booking->start_time,
            'end_time' => $booking->end_time,
            'session_status_id' => UserSessionStatusEnum::ID[UserSessionStatusEnum::PENDING],
            'booking_id' => $booking->id,
            'is_active' => false,
            'duration' => $duration
        ]);
    }

    private function isWinterSeason(Carbon $currentDate, $winterStartDate)
    {
        $winterStart = Carbon::parse($winterStartDate);

        return $currentDate->greaterThanOrEqualTo($winterStart);
    }

    private function getOperatingHours($dayOfWeek, $seasonHours)
    {
        foreach ($seasonHours as $hour) {
            if (strtolower($hour['day']) === strtolower($dayOfWeek)) {
                return [
                    'open' => $hour['open_time'],
                    'close' => $hour['close_time']
                ];
            }
        }

        return null;
    }
}
