<?php

namespace Modules\Hotel\Livewire\Forms;

use Modules\Hotel\Entities\Reservation;
use Modules\Hotel\Entities\Guest;
use Modules\Hotel\Entities\RoomType;
use Modules\Hotel\Entities\RatePlan;
use Modules\Hotel\Entities\ReservationRoom;
use Modules\Hotel\Enums\ReservationStatus;
use Modules\Hotel\Helpers\HotelHelper;
use Jantinnerezo\LivewireAlert\LivewireAlert;
use Livewire\Component;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;

class AddReservation extends Component
{
    use LivewireAlert;

    public $primary_guest_id;
    public $check_in_date;
    public $check_out_date;
    public $check_in_time;
    public $check_out_time;
    public $adults = 1;
    public $children = 0;
    public $rate_plan_id;
    public $status = ReservationStatus::TENTATIVE->value;
    public $special_requests;
    public $advance_paid = 0;
    public $selectedRooms = [];
    public $availableRooms = [];

    /**
     * Get statuses that can be selected from the form.
     * Only Tentative and Confirmed are allowed from here.
     *
     * @return array<ReservationStatus>
     */
    protected function allowedStatuses(): array
    {
        return [
            ReservationStatus::TENTATIVE,
            ReservationStatus::CONFIRMED,
        ];
    }

    public function mount()
    {
        $this->check_in_date = now()->format('Y-m-d');
        $this->check_out_date = now()->addDay()->format('Y-m-d');
        $this->check_in_time = '14:00';
        $this->check_out_time = '11:00';
    }

    public function updatedCheckInDate()
    {
        $this->checkAvailability();
    }

    public function updatedCheckOutDate()
    {
        $this->checkAvailability();
    }

    public function checkAvailability()
    {
        if (!$this->check_in_date || !$this->check_out_date) {
            return;
        }

        $checkIn = Carbon::parse($this->check_in_date);
        $checkOut = Carbon::parse($this->check_out_date);

        if ($checkOut < $checkIn) {
            $this->alert('error', __('hotel::modules.reservation.checkOutNotBeforeCheckIn'), [
                'toast' => true,
                'position' => 'top-end',
                'showCancelButton' => false,
                'cancelButtonText' => __('app.close')
            ]);
            return;
        }

        // For same-day stays, check availability for a minimum 1-day window
        $checkOutForAvailability = $checkOut->equalTo($checkIn) ? $checkOut->copy()->addDay() : $checkOut;

        $roomTypes = RoomType::where('is_active', true)->get();
        $this->availableRooms = [];

        foreach ($roomTypes as $roomType) {
            $availability = HotelHelper::getRoomAvailability($roomType->id, $checkIn, $checkOutForAvailability);
            $this->availableRooms[$roomType->id] = [
                'room_type' => $roomType,
                'available' => $availability,
                'quantity' => 0,
                'rate' => $roomType->base_rate,
            ];
        }
    }

    public function submitForm()
    {
        $this->validate([
            'primary_guest_id' => 'required|exists:hotel_guests,id',
            'check_in_date' => 'required|date',
            'check_out_date' => 'required|date|after_or_equal:check_in_date',
            'check_in_time' => 'nullable|date_format:H:i',
            'check_out_time' => 'nullable|date_format:H:i',
            'adults' => 'required|integer|min:1',
            'children' => 'integer|min:0',
            'rate_plan_id' => 'nullable|exists:hotel_rate_plans,id',
            'status' => 'required|in:' . implode(',', array_column($this->allowedStatuses(), 'value')),
        ]);

        $checkIn = Carbon::parse($this->check_in_date);
        $checkOut = Carbon::parse($this->check_out_date);

        if ($checkOut->lt($checkIn)) {
            $this->addError('check_out_date', __('hotel::modules.reservation.checkOutNotBeforeCheckIn'));
            return;
        }

        // If same-day stay, ensure check-out time is after check-in time
        if ($checkOut->equalTo($checkIn)) {
            if (!$this->check_in_time || !$this->check_out_time) {
                $this->addError('check_out_time', __('hotel::modules.reservation.checkOutTimeAfterCheckInTime'));
                return;
            }

            $checkInAt = Carbon::createFromFormat('Y-m-d H:i', $this->check_in_date . ' ' . $this->check_in_time);
            $checkOutAt = Carbon::createFromFormat('Y-m-d H:i', $this->check_out_date . ' ' . $this->check_out_time);
            if ($checkOutAt->lte($checkInAt)) {
                $this->addError('check_out_time', __('hotel::modules.reservation.checkOutTimeAfterCheckInTime'));
                return;
            }
        }

        $totalQuantity = collect($this->selectedRooms)->sum(fn ($room) => (int) ($room['quantity'] ?? 0));
        if (empty($this->selectedRooms) || !$totalQuantity) {
            $this->alert('error', __('hotel::modules.reservation.selectAtLeastOneRoom'), [
                'toast' => true,
                'position' => 'top-end',
                'showCancelButton' => false,
                'cancelButtonText' => __('app.close')
            ]);
            return;
        }

        // Minimum 1 night charge for same-day stays
        $nights = max(1, $checkIn->diffInDays($checkOut));

        $reservation = Reservation::create([
            'restaurant_id' => restaurant()->id,
            'branch_id' => branch()?->id,
            'reservation_number' => Reservation::generateReservationNumber(branch()?->id),
            'primary_guest_id' => $this->primary_guest_id,
            'check_in_date' => $this->check_in_date,
            'check_out_date' => $this->check_out_date,
            'check_in_time' => $this->check_in_time,
            'check_out_time' => $this->check_out_time,
            'adults' => $this->adults,
            'children' => $this->children,
            'rate_plan_id' => $this->rate_plan_id,
            'status' => $this->status,
            'special_requests' => $this->special_requests,
            'advance_paid' => $this->advance_paid,
            'rooms_count' => collect($this->selectedRooms)->sum(fn ($room) => (int) ($room['quantity'] ?? 0)),
            'total_amount' => 0,
            'created_by' => Auth::id(),
        ]);

        $totalAmount = 0;
        foreach ($this->selectedRooms as $roomTypeId => $roomData) {
            if ($roomData['quantity'] > 0) {
                $roomType = RoomType::find($roomTypeId);
                $rate = $roomData['rate'] ?? $roomType->base_rate;
                $amount = $rate * $nights * $roomData['quantity'];

                ReservationRoom::create([
                    'reservation_id' => $reservation->id,
                    'room_type_id' => $roomTypeId,
                    'quantity' => $roomData['quantity'],
                    'rate' => $rate,
                    'total_amount' => $amount,
                ]);

                $totalAmount += $amount;
            }
        }

        $reservation->update(['total_amount' => $totalAmount]);

        $this->reset();
        $this->dispatch('hideAddReservation');
        $this->dispatch('reservationAdded');

        $this->alert('success', __('hotel::modules.reservation.reservationCreated'), [
            'toast' => true,
            'position' => 'top-end',
            'showCancelButton' => false,
            'cancelButtonText' => __('app.close')
        ]);
    }

    public function render()
    {
        if ($this->check_in_date && $this->check_out_date) {
            $this->checkAvailability();
        }

        return view('hotel::livewire.forms.add-reservation', [
            'guests' => Guest::orderBy('first_name')->get(),
            'ratePlans' => RatePlan::where('is_active', true)->get(),
            'statuses' => $this->allowedStatuses(),
        ]);
    }
}
