<?php

namespace Modules\Hotel\Livewire\Forms;

use Modules\Hotel\Entities\Reservation;
use Modules\Hotel\Entities\Guest;
use Modules\Hotel\Entities\Quotation;
use Modules\Hotel\Entities\RoomType;
use Modules\Hotel\Entities\RatePlan;
use Modules\Hotel\Entities\ReservationRoom;
use Modules\Hotel\Entities\ReservationGuest;
use Modules\Hotel\Entities\ReservationExtra;
use Modules\Hotel\Entities\Tax;
use Modules\Hotel\Entities\ExtraService;
use Modules\Hotel\Enums\ReservationStatus;
use Modules\Hotel\Enums\PricingType;
use Modules\Hotel\Helpers\HotelHelper;
use App\Helper\Files;
use Jantinnerezo\LivewireAlert\LivewireAlert;
use Livewire\Component;
use Livewire\WithFileUploads;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Modules\Hotel\Notifications\HotelReservationCreated;

class AddReservation extends Component
{
    use LivewireAlert, WithFileUploads;

    public $guests = [];
    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 $pricing_type = 'daily';
    public $status = ReservationStatus::TENTATIVE->value;
    public $special_requests;
    public $advance_paid = 0;
    public $security_deposit = 0;
    public $selectedRooms = [];
    public $availableRooms = [];
    public $reason_for_trip;
    public $means_of_transport;
    public $place_of_origin;
    public $vehicle_registration_number;
    public $final_destination;
    public $apply_discount = false;
    public $discount_type = 'percentage';
    public $discount_value = 0;
    public $tax_id;
    public $tax_ids = [];
    public $advance_payment_method;
    public $selectedExtras = [];
    public $roomsTotal = 0;
    public $extrasTotal = 0;
    public $subTotal = 0;
    public $discountAmount = 0;
    public $taxAmount = 0;
    public $totalAmount = 0;
    public $amountAfterDiscount = 0;
    public $remainingBalance = 0;

    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';
        $this->addGuest();

        $fromQuotationId = (int) (request()->get('fromQuotation') ?? 0);
        if ($fromQuotationId > 0 && user_can('Create Hotel Reservation')) {
            $quotation = Quotation::with([
                'primaryGuest',
                'tax',
                'quotationRooms',
                'quotationExtras',
            ])->find($fromQuotationId);

            if ($quotation) {
                $this->check_in_date = optional($quotation->check_in_date)->format('Y-m-d') ?: $this->check_in_date;
                $this->check_out_date = optional($quotation->check_out_date)->format('Y-m-d') ?: $this->check_out_date;
                $this->check_in_time = $quotation->check_in_time ? Carbon::parse($quotation->check_in_time)->format('H:i') : $this->check_in_time;
                $this->check_out_time = $quotation->check_out_time ? Carbon::parse($quotation->check_out_time)->format('H:i') : $this->check_out_time;
                $this->adults = (int) ($quotation->adults ?? $this->adults);
                $this->children = (int) ($quotation->children ?? $this->children);
                $this->rate_plan_id = $quotation->rate_plan_id;
                $this->special_requests = $quotation->special_requests;
                $this->advance_paid = (float) ($quotation->advance_paid ?? 0);
                $this->advance_payment_method = $quotation->advance_payment_method;

                $this->discount_type = $quotation->discount_type ?? $this->discount_type;
                $this->discount_value = (float) ($quotation->discount_value ?? 0);
                $this->apply_discount = $this->discount_value > 0;
                $this->tax_id = $quotation->tax_id;
                $this->tax_ids = $quotation->tax_id ? [(int) $quotation->tax_id] : [];

                $this->guests = [[
                    'first_name' => $quotation->primaryGuest?->first_name ?? '',
                    'last_name' => $quotation->primaryGuest?->last_name ?? '',
                    'email' => $quotation->primaryGuest?->email ?? '',
                    'phone' => $quotation->primaryGuest?->phone ?? '',
                    'id_type' => $quotation->primaryGuest?->id_type ?? 'passport',
                    'id_number' => $quotation->primaryGuest?->id_number ?? '',
                    'id_proof_file' => null,
                ]];

                $this->selectedRooms = [];
                foreach ($quotation->quotationRooms as $qr) {
                    $this->selectedRooms[$qr->room_type_id] = [
                        'quantity' => (int) ($qr->quantity ?? 0),
                        'rate' => (float) ($qr->rate ?? 0),
                    ];
                }

                $this->selectedExtras = [];
                foreach ($quotation->quotationExtras as $qe) {
                    $this->selectedExtras[$qe->extra_service_id] = [
                        'quantity' => (int) ($qe->quantity ?? 0),
                        'unit_price' => (float) ($qe->unit_price ?? 0),
                    ];
                }
            }
        }

        $this->checkAvailability();
        $this->syncSelectedExtrasFromCatalog();
        $this->refreshBookingTotals();
    }

    /**
     * Ensure extra rows exist with stable wire:model keys (qty + unit price).
     */
    protected function syncSelectedExtrasFromCatalog(): void
    {
        foreach (ExtraService::where('is_active', true)->get() as $extra) {
            $existing = $this->selectedExtras[$extra->id] ?? [];
            $qty = isset($existing['quantity']) ? (int) $existing['quantity'] : 0;
            $unitPrice = $existing['unit_price'] ?? $extra->price;
            if ($unitPrice === '' || $unitPrice === null) {
                $unitPrice = (float) $extra->price;
            } else {
                $unitPrice = (float) $unitPrice;
            }
            $this->selectedExtras[$extra->id] = [
                'quantity' => max(0, $qty),
                'unit_price' => max(0, $unitPrice),
            ];
        }
    }

    public function reservationNights(): int
    {
        if (!$this->check_in_date || !$this->check_out_date) {
            return 1;
        }

        return max(1, Carbon::parse($this->check_in_date)->diffInDays(Carbon::parse($this->check_out_date)));
    }

    /**
     * Returns the billable room units based on the reservation-level pricing_type.
     *
     * We treat room rate as a DAILY rate (per night), and multiply by:
     * - Daily: number of nights
     * - Weekly: ceil(nights / 7) * 7
     * - Biweekly: ceil(nights / 14) * 14
     * - Monthly: ceil(nights / 30) * 30
     * - Custom: 1 (one-time)
     */
    public function getRoomPeriods(int|string $roomTypeId = 0): int
    {
        $days = $this->reservationNights();

        return match($this->pricing_type) {
            'weekly'   => max(1, (int) ceil($days / 7)) * 7,
            'biweekly' => max(1, (int) ceil($days / 14)) * 14,
            'monthly'  => max(1, (int) ceil($days / 30)) * 30,
            'custom'   => 1,
            default    => $days, // daily
        };
    }

    /**
     * Returns each pricing type with label and pre-calculated total so the UI can show radio buttons.
     */
    public function getPricingTypeOptions(): array
    {
        $options = [];
        $days = $this->reservationNights();

        $roomsBaseTotal = 0;
        foreach ($this->selectedRooms ?? [] as $roomTypeId => $roomData) {
            $qty = (int) ($roomData['quantity'] ?? 0);
            if ($qty > 0) {
                $defaultRate = (float) ($this->availableRooms[$roomTypeId]['base_rate'] ?? 0);
                $rateInput   = $roomData['rate'] ?? null;
                $rate        = ($rateInput === '' || $rateInput === null) ? $defaultRate : (float) $rateInput;
                $roomsBaseTotal += $rate * $qty; // rate per period × qty
            }
        }

        foreach (PricingType::cases() as $type) {
            $billableUnits = match($type->value) {
                'weekly'   => max(1, (int) ceil($days / 7)) * 7,
                'biweekly' => max(1, (int) ceil($days / 14)) * 14,
                'monthly'  => max(1, (int) ceil($days / 30)) * 30,
                'custom'   => 1,
                default    => $days,
            };
            $options[] = [
                'value'   => $type->value,
                'label'   => $type->label(),
                'periods' => $billableUnits,
                'total'   => round($roomsBaseTotal * $billableUnits, 2),
            ];
        }

        return $options;
    }

    public function updatedPricingType(): void
    {
        $this->refreshBookingTotals();
    }

    public function updatedSelectedRooms(): void
    {
        foreach ($this->availableRooms as $roomTypeId => $meta) {
            if (!isset($this->selectedRooms[$roomTypeId])) {
                continue;
            }
            $qty = max(0, (int) ($this->selectedRooms[$roomTypeId]['quantity'] ?? 0));
            $max = (int) ($meta['available'] ?? 0);
            if ($qty > $max) {
                $qty = $max;
            }
            $this->selectedRooms[$roomTypeId]['quantity'] = $qty;
        }

        $this->refreshBookingTotals();
    }

    public function updatedSelectedExtras(): void
    {
        foreach (array_keys($this->selectedExtras) as $extraId) {
            $row = $this->selectedExtras[$extraId];
            $this->selectedExtras[$extraId]['quantity'] = max(0, (int) ($row['quantity'] ?? 0));
            $price = $row['unit_price'] ?? null;
            if ($price !== '' && $price !== null && (float) $price < 0) {
                $this->selectedExtras[$extraId]['unit_price'] = 0;
            }
        }

        $this->refreshBookingTotals();
    }

    /**
     * Sync public summary fields used in the Blade sidebar (must run after rooms/extras/discount/tax inputs change).
     */
    protected function refreshBookingTotals(): void
    {
        $this->subTotal = round((float) $this->Subtotal(), 2);
        $this->roomsTotal = round((float) $this->RoomsTotal(), 2);
        $this->extrasTotal = round((float) $this->ExtrasTotal(), 2);
        $this->discountAmount = round((float) $this->DiscountAmount(), 2);
        $this->taxAmount = round((float) $this->TaxAmount(), 2);
        $this->totalAmount = round((float) $this->TotalAmount(), 2);
        $this->amountAfterDiscount = round((float) $this->AmountAfterDiscount(), 2);
        $this->remainingBalance = round((float) $this->RemainingBalance(), 2);
    }

    public function updatedApplyDiscount(): void
    {
        $this->refreshBookingTotals();
    }

    public function updatedDiscountType(): void
    {
        $this->refreshBookingTotals();
    }

    public function updatedDiscountValue(): void
    {
        $this->refreshBookingTotals();
    }

    public function updatedRatePlanId(): void
    {
        if ($this->rate_plan_id === '') {
            $this->rate_plan_id = null;
        } elseif ($this->rate_plan_id !== null) {
            $this->rate_plan_id = (int) $this->rate_plan_id;
        }
    }

    public function updatedTaxId(): void
    {
        if ($this->tax_id === '') {
            $this->tax_id = null;
        } elseif ($this->tax_id !== null) {
            $this->tax_id = (int) $this->tax_id;
        }
        $this->refreshBookingTotals();
    }

    public function updatedTaxIds(): void
    {
        $this->tax_ids = array_values(array_unique(array_filter(array_map('intval', (array) $this->tax_ids))));
        $this->tax_id = $this->tax_ids[0] ?? null; // backward compatibility for existing single-tax usage
        $this->refreshBookingTotals();
    }

    public function updatedAdvancePaid(): void
    {
        if ($this->advance_paid === '' || $this->advance_paid === null) {
            $this->advance_paid = 0;
        }
        $this->refreshBookingTotals();
    }

    public function updatedSecurityDeposit(): void
    {
        if ($this->security_deposit === '' || $this->security_deposit === null) {
            $this->security_deposit = 0;
        }
        $this->refreshBookingTotals();
    }

    public function roomLineTotal(int|string $roomTypeId): float
    {
        $roomTypeId = (int) $roomTypeId;
        $roomData   = $this->selectedRooms[$roomTypeId] ?? null;
        if (!$roomData) {
            return 0.0;
        }
        $qty = (int) ($roomData['quantity'] ?? 0);
        if ($qty <= 0) {
            return 0.0;
        }
        $defaultRate = (float) ($this->availableRooms[$roomTypeId]['base_rate'] ?? 0);
        $rateInput   = $roomData['rate'] ?? null;
        $rate        = ($rateInput === '' || $rateInput === null) ? $defaultRate : (float) $rateInput;
        $periods     = $this->getRoomPeriods($roomTypeId);

        return round($rate * $periods * $qty, 2);
    }

    public function extraLineTotal(int|string $extraId, float $defaultUnitPrice): float
    {
        $extraId = (int) $extraId;
        $extraData = $this->selectedExtras[$extraId] ?? null;
        if (!$extraData) {
            return 0.0;
        }
        $qty = (int) ($extraData['quantity'] ?? 0);
        if ($qty <= 0) {
            return 0.0;
        }
        $priceInput = $extraData['unit_price'] ?? null;
        $price = ($priceInput === '' || $priceInput === null)
            ? $defaultUnitPrice
            : (float) $priceInput;

        return round($price * $qty, 2);
    }

    public function addGuest()
    {
        $this->guests[] = [
            'first_name' => '',
            'last_name' => '',
            'email' => '',
            'phone' => '',
            'id_type' => 'passport',
            'id_number' => '',
            'id_proof_file' => null,
        ];
    }

    public function removeGuest($index)
    {
        // Single guest mode for reservation form.
        return;
    }

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

    public function updatedCheckOutDate(): void
    {
        $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) {
            return;
        }

        $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);
            $existing = $this->selectedRooms[$roomType->id] ?? [];
            $qty = isset($existing['quantity']) ? (int) $existing['quantity'] : 0;
            $rate = $existing['rate'] ?? $roomType->base_rate;
            if ($rate === '' || $rate === null) {
                $rate = $roomType->base_rate;
            } else {
                $rate = (float) $rate;
            }
            $this->selectedRooms[$roomType->id] = ['quantity' => $qty, 'rate' => $rate];
            $this->availableRooms[$roomType->id] = [
                'room_type_id'   => $roomType->id,
                'room_type_name' => $roomType->name,
                'base_rate'      => (float) $roomType->base_rate,
                'available'      => max($availability, $qty),
                'quantity'       => $qty,
                'rate'           => $rate,
            ];
        }

        $this->refreshBookingTotals();
    }

    public function Subtotal()
    {
        $roomsTotal = 0;
        foreach ($this->selectedRooms ?? [] as $roomTypeId => $roomData) {
            $qty = (int) ($roomData['quantity'] ?? 0);
            if ($qty > 0) {
                $defaultRate = (float) ($this->availableRooms[$roomTypeId]['base_rate'] ?? 0);
                $rateInput   = $roomData['rate'] ?? null;
                $rate        = ($rateInput === '' || $rateInput === null) ? $defaultRate : (float) $rateInput;
                $periods     = $this->getRoomPeriods($roomTypeId);
                $roomsTotal += $rate * $periods * $qty;
            }
        }

        $extrasTotal = 0;
        foreach ($this->selectedExtras ?? [] as $extraId => $extraData) {
            $qty = (int) ($extraData['quantity'] ?? 0);
            if ($qty > 0) {
                $defaultPrice = (float) (ExtraService::find($extraId)?->price ?? 0);
                $priceInput = $extraData['unit_price'] ?? null;
                $price = ($priceInput === '' || $priceInput === null)
                    ? $defaultPrice
                    : (float) $priceInput;
                $extrasTotal += $price * $qty;
            }
        }

        return $roomsTotal + $extrasTotal;
    }

    public function DiscountAmount()
    {
        if (!$this->apply_discount) {
            return 0;
        }

        $subtotal = $this->subTotal;
        if (!$this->discount_value || $this->discount_value <= 0) {
            return 0;
        }
        if ($this->discount_type === 'percentage') {
            return round($subtotal * ($this->discount_value / 100), 2);
        }

        return round((float) min($this->discount_value, $subtotal), 2);
    }

    public function TaxAmount()
    {
        $afterDiscount = $this->subTotal - $this->discountAmount;
        $taxIds = array_values(array_unique(array_filter(array_map('intval', (array) $this->tax_ids))));

        if (empty($taxIds)) {
            return 0;
        }

        $rateSum = (float) Tax::whereIn('id', $taxIds)->sum('rate');

        return round($afterDiscount * ($rateSum / 100), 2);
    }

    public function TotalAmount()
    {
        return round($this->subTotal - $this->discountAmount + $this->taxAmount, 2);
    }

    /**
     * Net after discount, before tax (tax base).
     */
    public function AmountAfterDiscount()
    {
        return max(0, round($this->subTotal - $this->discountAmount, 2));
    }

    /**
     * Amount still to collect at checkout (total minus advance); never negative.
     */
    public function RemainingBalance()
    {
        $advance = (float) ($this->advance_paid ?? 0);
        $deposit = (float) ($this->security_deposit ?? 0);

        return max(0, round($this->totalAmount - $advance - $deposit, 2));
    }

    public function RoomsTotal()
    {
        $nights = $this->reservationNights();

        $total = 0;
        foreach ($this->selectedRooms ?? [] as $roomTypeId => $roomData) {
            $qty = (int) ($roomData['quantity'] ?? 0);
            if ($qty > 0) {
                $defaultRate = $this->availableRooms[$roomTypeId]['base_rate'] ?? 0;
                $rateInput   = $roomData['rate'] ?? null;
                $rate        = ($rateInput === '' || $rateInput === null) ? (float) $defaultRate : (float) $rateInput;
                $periods     = $this->getRoomPeriods($roomTypeId);
                $total      += $rate * $periods * $qty;
            }
        }
        return $total;
    }

    public function ExtrasTotal()
    {
        $total = 0;
        foreach ($this->selectedExtras ?? [] as $extraId => $extraData) {
            $qty = (int) ($extraData['quantity'] ?? 0);
            if ($qty > 0) {
                $defaultPrice = (float) (ExtraService::find($extraId)?->price ?? 0);
                $priceInput = $extraData['unit_price'] ?? null;
                $price = ($priceInput === '' || $priceInput === null)
                    ? $defaultPrice
                    : (float) $priceInput;
                $total += $price * $qty;
            }
        }
        return $total;
    }

    protected function normalizeReservationFormInputs(): void
    {
        $this->rate_plan_id = ($this->rate_plan_id === '' || $this->rate_plan_id === false)
            ? null
            : (is_numeric($this->rate_plan_id) ? (int) $this->rate_plan_id : null);
        $this->tax_id = ($this->tax_id === '' || $this->tax_id === false)
            ? null
            : (is_numeric($this->tax_id) ? (int) $this->tax_id : null);
        $this->advance_paid = ($this->advance_paid === '' || $this->advance_paid === null) ? 0 : $this->advance_paid;
        $this->security_deposit = ($this->security_deposit === '' || $this->security_deposit === null) ? 0 : $this->security_deposit;
        $this->discount_value = ($this->discount_value === '' || $this->discount_value === null) ? 0 : $this->discount_value;
        $this->children = (int) (($this->children === '' || $this->children === null) ? 0 : $this->children);
    }

    public function submitForm()
    {
        // Reservation form currently supports exactly one guest.
        $this->guests = [array_values($this->guests)[0] ?? [
            'first_name' => '',
            'last_name' => '',
            'email' => '',
            'phone' => '',
            'id_type' => 'passport',
            'id_number' => '',
            'id_proof_file' => null,
        ]];

        $this->normalizeReservationFormInputs();

        $attributes = (array) __('hotel::modules.validation.attributes');

        $this->validate([
            'guests' => 'required|array|min:1',
            'guests.*.first_name' => 'required|string|max:255',
            'guests.*.last_name' => 'nullable|string|max:255',
            'guests.*.email' => 'nullable|email|max:255',
            'guests.*.phone' => 'required|numeric|min:10',
            'guests.*.id_type' => 'required|string|max:255',
            'guests.*.id_number' => 'required|numeric|min:10',
            'guests.*.id_proof_file' => 'nullable|file|mimes:jpeg,jpg,png,gif,webp,pdf|max:5120',
            '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|integer|exists:hotel_rate_plans,id',
            'status' => 'required|in:' . implode(',', array_column($this->allowedStatuses(), 'value')),
            'advance_paid' => 'nullable|numeric|min:0',
            'security_deposit' => 'nullable|numeric|min:0',
            'discount_type' => 'nullable|in:percentage,fixed',
            'discount_value' => 'nullable|numeric|min:0',
            'tax_ids' => 'nullable|array',
            'tax_ids.*' => 'integer|exists:hotel_taxes,id',
        ], [], $attributes);

        if (((float) ($this->advance_paid ?? 0) > 0 || (float) ($this->security_deposit ?? 0) > 0) && blank($this->advance_payment_method)) {
            $this->addError('advance_payment_method', __('validation.required'));
            return;
        }

        $this->refreshBookingTotals();

        $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 ($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;
        }

        // kept for extras / legacy; per-room periods used below
        $nights = max(1, $checkIn->diffInDays($checkOut));

        // Create a single primary guest record.
        $guestData = $this->guests[0];
        $idProofPath = null;
        if (!empty($guestData['id_proof_file']) && is_object($guestData['id_proof_file'])) {
            $idProofPath = Files::uploadLocalOrS3($guestData['id_proof_file'], 'guest-id-proof');
        }

        $guest = Guest::create([
            'restaurant_id' => restaurant()->id,
            'branch_id' => branch()?->id,
            'first_name' => $guestData['first_name'],
            'last_name' => $guestData['last_name'] ?: null,
            'email' => $guestData['email'] ?: null,
            'phone' => $guestData['phone'],
            'id_type' => $guestData['id_type'],
            'id_number' => $guestData['id_number'],
            'id_proof_file' => $idProofPath,
        ]);

        $primaryGuestId = $guest->id;

        $subtotal = $this->subTotal;
        $discountAmount = $this->discountAmount;
        $taxAmount = $this->taxAmount;
        $totalAmount = $this->totalAmount;

        $reservation = Reservation::create([
            'restaurant_id' => restaurant()->id,
            'branch_id' => branch()?->id,
            'reservation_number' => Reservation::generateReservationNumber(branch()?->id),
            'primary_guest_id' => $primaryGuestId,
            '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,
            'pricing_type' => $this->pricing_type,
            'status' => $this->status,
            'special_requests' => $this->special_requests,
            'advance_paid' => $this->advance_paid,
            'security_deposit' => $this->security_deposit,
            'reason_for_trip' => $this->reason_for_trip,
            'means_of_transport' => $this->means_of_transport,
            'place_of_origin' => $this->place_of_origin,
            'vehicle_registration_number' => $this->vehicle_registration_number,
            'final_destination' => $this->final_destination,
            'discount_type' => $this->apply_discount ? $this->discount_type : null,
            'discount_value' => $this->apply_discount ? $this->discount_value : 0,
            'tax_id' => $this->tax_ids[0] ?? null,
            'advance_payment_method' => (float) ($this->advance_paid ?? 0) > 0 ? $this->advance_payment_method : null,
            'subtotal_before_tax' => $subtotal - $discountAmount,
            'tax_amount' => $taxAmount,
            'extras_amount' => $this->extrasTotal,
            'rooms_count' => collect($this->selectedRooms)->sum(fn ($room) => (int) ($room['quantity'] ?? 0)),
            'total_amount' => $totalAmount,
            'created_by' => Auth::id(),
        ]);

        $reservation->taxes()->sync(array_values(array_unique(array_filter(array_map('intval', (array) $this->tax_ids)))));

        ReservationGuest::create([
            'reservation_id' => $reservation->id,
            'guest_id' => $guest->id,
            'is_primary' => true,
            'sort_order' => 0,
        ]);

        foreach ($this->selectedRooms as $roomTypeId => $roomData) {
            if (($roomData['quantity'] ?? 0) > 0) {
                $roomType  = RoomType::find($roomTypeId);
                $rateInput = $roomData['rate'] ?? null;
                $rate      = ($rateInput === '' || $rateInput === null)
                    ? (float) $roomType->base_rate
                    : (float) $rateInput;
                $periods   = $this->getRoomPeriods($roomTypeId);
                $amount    = $rate * $periods * $roomData['quantity'];
                ReservationRoom::create([
                    'reservation_id' => $reservation->id,
                    'room_type_id'   => $roomTypeId,
                    'quantity'       => $roomData['quantity'],
                    'rate'           => $rate,
                    'total_amount'   => $amount,
                ]);
            }
        }

        foreach ($this->selectedExtras ?? [] as $extraId => $extraData) {
            if (($extraData['quantity'] ?? 0) > 0) {
                $defaultPrice = (float) (ExtraService::find($extraId)?->price ?? 0);
                $unitPriceInput = $extraData['unit_price'] ?? null;
                $unitPrice = ($unitPriceInput === '' || $unitPriceInput === null)
                    ? $defaultPrice
                    : (float) $unitPriceInput;
                $total = $unitPrice * $extraData['quantity'];
                ReservationExtra::create([
                    'reservation_id' => $reservation->id,
                    'extra_service_id' => $extraId,
                    'quantity' => $extraData['quantity'],
                    'unit_price' => $unitPrice,
                    'total_amount' => $total,
                ]);
            }
        }

        if (!blank($guest->email)) {
            try {
                $reservation->load([
                    'restaurant',
                    'branch',
                    'primaryGuest',
                    'tax',
                    'taxes',
                    'reservationRooms.roomType',
                    'reservationExtras.extraService',
                ]);

                Notification::route('mail', $guest->email)
                    ->notify(new HotelReservationCreated($reservation));
            } catch (\Throwable $e) {
                Log::error('Error sending hotel reservation created email: ' . $e->getMessage(), [
                    'reservation_id' => $reservation->id,
                    'guest_id' => $guest->id,
                    'email' => $guest->email,
                ]);
            }
        }

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

        return $this->redirect(route('hotel.reservations.index'), navigate: true);
    }

    public function render()
    {
        return view('hotel::livewire.forms.add-reservation', [
            'ratePlans'          => RatePlan::where('is_active', true)->get(),
            'statuses'           => $this->allowedStatuses(),
            'taxes'              => Tax::where('is_active', true)->get(),
            'extraServices'      => ExtraService::where('is_active', true)->get(),
            'pricingTypeOptions' => $this->getPricingTypeOptions(),
        ]);
    }
}
