<?php

namespace App\Http\Controllers\Apis;

//* Packages and Libraries
    use App\Http\Controllers\Controller;
    use Illuminate\Http\Request;
    use Carbon\Carbon;
    use stdClass;

//* Modules
    // Restaurant
    use App\Models\Restaurant\Order;
    use App\Models\Restaurant\Product;
    use App\Models\Restaurant\Table;

    // Hotel
    use App\Models\Hotel\Agency;
    use App\Models\Hotel\Client;
    use App\Models\Hotel\Reservation;
    use App\Models\Hotel\Room;
    use App\Models\Hotel\RoomType;

    use App\Models\Hotel\ConsumptionCharges;
    use App\Models\Hotel\ConsumptionPayments;
    use App\Models\Hotel\ExtraCharges;
    use App\Models\Hotel\ExtraPayments;
    use App\Models\Hotel\LodgingPayments;

    //Settings
    use App\Models\User;

//* Helpers
    use App\Helpers\Environment\SystemParametersHelper;
    use App\Helpers\Formats\LangHelper;

class ApiController extends Controller
{
  //* Constructor
    public function __construct() {
        $this->middleware('auth');
    }

  //* Special Functions
    // Summaries
    public function getHotelSummary(){

        $room = Room::select('id')->count();
        $roomType = RoomType::select('id')->count();
        $agencies = Agency::select('id')->count();

        $reservations = Reservation::whereMonth('date_entry', Carbon::now())->count();
        $checkouts = Reservation::where('guest_status_id','=','6')
                        ->whereMonth('date_entry', Carbon::now())->count();

        // Hospedaje
        $lodgingEarnings = LodgingPayments::whereMonth('payment_date', Carbon::now())->where('status', 'Activo')->sum('payment_price');
        // Extras
        $extraEarningsM = ExtraPayments::whereMonth('payment_date', Carbon::now())->where('status', 'Activo')->sum('payment_price');
        // Consumo
        $consumptionEarningsM = ConsumptionPayments::whereMonth('payment_date', Carbon::now())->where('status', 'Activo')->sum('payment_price');
        // Total
        $total = $lodgingEarnings + $extraEarningsM + $consumptionEarningsM;
        $total = sprintf("%.2f", $total);

        $occupiedRooms = Reservation::where('guest_status_id','=','4')->count();
        $clients = Client::select('id')->count();

        $userManagers = User::where('role','gerente')->count();
        $userReceptionists = User::where('role','recepcionista')->count();
        $userAdmins = User::where('role','administrador')->count();
        $userTotal =  $userManagers + $userReceptionists + $userAdmins;

            // Si la Fecha de hoy >= Fecha de Entrada y la fecha de hoy es <= Fecha de Salida, el Cliente esta en el Hotel
            // si la Fecha de Entrada <= la de hoy y Fecha de Salida > a la de hoy, el Cliente esta en el Hotel

        $response = [
            'room' => $room,
            'roomType' => $roomType,
            'agencies' => $agencies,
            'reservations' => $reservations,
            'checkouts' => $checkouts,
            'total' => $total,
            'lodgingEarnings' => $lodgingEarnings,
            'extraEarningsM' => $extraEarningsM,
            'consumptionEarningsM' => $consumptionEarningsM,
            'occupiedRooms' => $occupiedRooms,
            'clients' => $clients,
            'userTotal' => $userTotal,
        ];

        return $response;
    }

    public function getRestaurantSummary(){
        $orderMonth = Order::whereMonth('order_date', Carbon::now())->count();
        $orderDay = Order::whereDay('order_date', Carbon::now())->count();
        $tables = Table::select('id')->count();
        $saleMonth = Order::whereMonth('order_date', Carbon::now())->sum('order_total');
        $saleDay = Order::whereDay('order_date', Carbon::now())->sum('order_total');
        $products = Product::select('product_name')->count();


        $response = [
            'orderMonth' => $orderMonth,
            'orderDay' => $orderDay,
            'tables' => $tables,
            'saleMonth' => $saleMonth,
            'saleDay' => $saleDay,
            'products' => $products,
        ];

        return $response;
    }

    // For Home
    public function getReservationCards (Request $request){
      //* Control Data
        // Time Controls
        $now = Carbon::now();
        $today = $now->format('Y-m-d');

        $use_hours = $request->boolean('has_control_hours');
        $express_checkout_minutes = SystemParametersHelper::getValueOf('hotel.express_checkout_minutes') ?? 11;
        $time_window = 15;

        // Reserves
        $reservations = Reservation::with('client')
            ->where('status_id','!=',7)// Avoid Cancelled Reserves
            ->where(function ($query) use ($now, $time_window) { // Only analyze nearly reserves
                $query->whereBetween('date_entry', [
                    $now->copy()->subDays($time_window)->toDateString(),
                    $now->copy()->addDays($time_window)->toDateString()
                ])
                ->orWhereBetween('date_departure', [
                    $now->copy()->subDays($time_window)->toDateString(),
                    $now->copy()->addDays($time_window)->toDateString()
                ]);
            })->get();

        // Data to return
        $arrivals = [];
        $departures = [];
        $occupancy = [];
        $forModal = [];

      //* Classify Reservations
        foreach ($reservations as $reservation){

          // Parse Times & Dates
            $entryDate = Carbon::parse($reservation->date_entry);
            $entryDateTime = Carbon::parse($reservation->date_entry . ' ' . $reservation->hour_entry);

            // $departureDate = Carbon::parse($reservation->date_departure);
            $departureDateTime = Carbon::parse($reservation->date_departure . ' ' . $reservation->hour_departure);

          // Pre-calculate next days (only needed for non-hour logic)
            $oneDayLater = $entryDate->copy()->addDay()->format('Y-m-d');
            // $twoDaysLater = $entryDate->copy()->addDays(2)->format('Y-m-d');

          // Classify
            // Support
            $status_id = $reservation->status['id'];
            $guest_status_id = $reservation->guestStatus['id'];

            //# Llegadas
            if (
                (//? Normal Reservations (ignore hours completely)
                    !$reservation->is_express &&
                    (
                        ($today === $reservation->date_entry //* Day of Entry
                        && $guest_status_id === 3) // Ninguno
                        ||
                        ($today === $oneDayLater //* After the First "No show"
                        && $guest_status_id === 5) // No se presenta
                        // ||
                        // ($today === $twoDaysLater
                        // && $reservation->show_in_calendar === 0  //* After the Second "No show"
                        // && $guest_status_id === 5) // No se presenta
                    )
                ) ||
                (//? Express Reservations (always use hours)
                    $reservation->is_express &&
                    $now->between( // Ensure only Check-in is today
                        $entryDateTime->copy()->startOfDay(),
                        $entryDateTime->copy()->endOfDay()
                    ) &&
                    $guest_status_id === 3 // Ninguno
                )
            ) {
                $arrivals[] = $this->buildReservationData($reservation, "arrive");
                $forModal[] = $this->buildReservationModal($reservation); // Modal Data
            }

            //# En el Hotel
            elseif (
                (//? Normal Reservations
                    !$reservation->is_express &&
                    /* (
                        (
                            !$use_hours && // Feature "has_control_hours"
                            ($today >= $reservation->date_entry && $today < $reservation->date_departure) // Use all day
                        )
                        ||
                        (
                            $use_hours && // Feature "has_control_hours"
                            $now >= $entryDateTime && $now < $departureDateTime // Use reservation time period
                        )
                    ) && */
                    $today >= $reservation->date_entry && $today < $reservation->date_departure && // Discomment only if system will skip hourly validation
                    ($guest_status_id == 4 && $status_id === 1 ) // Check-in && Confirmado
                ) ||
                (//? Express Reservations (always by hours)
                    $reservation->is_express &&
                    $now >= $entryDateTime && $now < $departureDateTime->copy()->subMinutes($express_checkout_minutes) &&
                    ($guest_status_id == 4 && $status_id === 1) // Check-in && Confirmado
                )
            ) {
                $occupancy[] = $this->buildReservationData($reservation, "ocupancy");
                $forModal[] = $this->buildReservationModal($reservation); // Modal Data
            }

            //# Salidas
            elseif (
                (//? Normal Reservations
                    !$reservation->is_express &&
                    // (
                    //     (
                    //         !$use_hours && // Feature "has_control_hours"
                    //         $reservation->date_departure <= $today // Use all day
                    //     )
                    //     ||
                    //     (
                    //         $use_hours && // Feature "has_control_hours"
                    //         $now >= $departureDateTime // Use reservation time period
                    //     )
                    // ) &&
                    $reservation->date_departure <= $today && // Discomment only if system will skip hourly validation
                    !in_array($guest_status_id, [6, 5]) && // [Check-out, No se presenta]
                    $status_id === 1 // Confirmado
                ) ||
                (//? Express Reservations (always by hours)
                    $reservation->is_express && $now >= $departureDateTime->copy()->subMinutes($express_checkout_minutes) &&
                    !in_array($guest_status_id, [6, 5]) && // [Check-out, No se presenta]
                    $status_id === 1 // Confirmado
                )
            ) {
                $departures[] = $this->buildReservationData($reservation, "departure");
                $forModal[] = $this->buildReservationModal($reservation); // Modal Data
            }
        }

        // Ordenamos las Llegadas con base a su 'no_show_type'
            $order = [
                'Primary' => 1, // Normal Mode
                'Secondary' => 2, // With 1 "No show"
                'Tertiary' => 3 // With 2 "No show"
            ];

            usort($arrivals, function($a, $b) use ($order) {
                return $order[$a->no_show_type] <=> $order[$b->no_show_type];
            });

      // Build Return
        $data = (object) [
            "arrivals" => $arrivals,
            "departures" => $departures,
            "occupancy" => $occupancy,
            "modals" => $forModal,
        ];

        return response()->json($data);
    }

    public function buildReservationData($reservation, $control_status){

        $mutable = Carbon::now()->format('Y-m-d');
        $lodgingPayments = LodgingPayments::where('reservation_id',$reservation->id)->where('status', 'Activo')->sum('payment_price');
        $lodgingPayment_left = $reservation->total_price - $lodgingPayments;

        $reservation_data = new stdClass;

            //* Common
            $reservation_data->id = $reservation->id;
            $reservation_data->date_entry = $reservation->date_entry;
            $reservation_data->date_departure = $reservation->date_departure;
            $reservation_data->number_nights = $reservation->number_nights;
            $reservation_data->number_hours = $reservation->number_hours;
            $reservation_data->is_express = $reservation->is_express;
            $reservation_data->room_type = $reservation->roomType->tr_name;
            $reservation_data->room_number = $reservation->room->room_name;
            $reservation_data->number_adults = $reservation->number_adults;
            $reservation_data->number_children = $reservation->number_children;
            $reservation_data->client_reference = $reservation->client_reference;
            $reservation_data->client_segment_type = $reservation->client->segment_label;
            $reservation_data->client_segment_badge = $reservation->client->segment_badge;
            $reservation_data->payment_status = $reservation->payment_status;

            //* Only Arrives
                if($control_status === 'arrive'){
                    $reservation_data->show_in_calendar = $reservation->show_in_calendar; //

                    $reference_entry = Carbon::parse($reservation->date_entry);
                        $oneDayLater = $reference_entry->addDays(1);
                        $oneDayLater = $oneDayLater->format('Y-m-d');
                        // $twoDaysLater = $reference_entry->addDays(1);
                        // $twoDaysLater = $twoDaysLater->format('Y-m-d');

                    if($reservation->date_entry === $mutable){
                        $reservation_data->no_show_type = 'Primary'; // Normal Mode
                    } elseif ($mutable === $oneDayLater) {
                        $reservation_data->no_show_type = 'Secondary'; // With 1 "No show"
                    } // elseif ($mutable === $twoDaysLater) {
                    //     $reservation_data->no_show_type = 'Tertiary'; // With 2 "No show"
                    // }
                }

            //* Occupancy & Departures
                if(in_array($control_status, ['ocupancy', 'departure'])){
                    $reservation_data->lodgingPayments = $lodgingPayments;
                    $reservation_data->lodgingPayment_left = number_format($lodgingPayment_left, 2, '.', '');
                }

        return $reservation_data;
    }

    public function buildReservationModal($reservation){

        // Payment and Charges
        $lodgingPayments = LodgingPayments::where('reservation_id',$reservation->id)->where('status', 'Activo')->sum('payment_price');
        $extraPayments = ExtraPayments::where('reservation_id',$reservation->id)->where('status', 'Activo')->sum('payment_price');
        $consumptionPayments = ConsumptionPayments::where('reservation_id',$reservation->id)->where('status', 'Activo')->sum('payment_price');
        $extraCharges = ExtraCharges::where('reservation_id',$reservation->id)->where('status', 'Activo')->sum('extras_price');
        $consumptionCharges = ConsumptionCharges::where('reservation_id',$reservation->id)->where('status', 'Activo')->sum('consumption_price');

        // Saldos Restantes
        $lodgingPayment_left = $reservation->total_price - $lodgingPayments;
        $extraPayment_left = $extraCharges - $extraPayments;
        $consumptionPayment_left = $consumptionCharges - $consumptionPayments;

        // Ajuste de Deuda
        if ($lodgingPayment_left < 0) {
            $lodgingPayment_left = 0;
        }
        if ($extraPayment_left < 0) {
            $extraPayment_left = 0;
        }
        if ($consumptionPayment_left < 0) {
            $consumptionPayment_left = 0;
        }

        $modal_data = new stdClass;

            //* Basic Data

                // Of Creation
                $modal_data->id = $reservation->id;
                $modal_data->reservation_date = $reservation->reservation_date;

                // Of Registration
                $modal_data->client_reference = $reservation->client_reference;
                $modal_data->client_segment_type = $reservation->client->segment_label;
                $modal_data->client_segment_badge = $reservation->client->segment_badge;

                $modal_data->date_entry = $reservation->date_entry;
                $modal_data->hour_entry = $reservation->hour_entry;
                $modal_data->date_departure = $reservation->date_departure;
                $modal_data->hour_departure = $reservation->hour_departure;
                $modal_data->number_nights = $reservation->number_nights;
                $modal_data->number_hours = $reservation->number_hours;
                $modal_data->number_adults = $reservation->number_adults;
                $modal_data->number_children = $reservation->number_children;
                $modal_data->notes = $reservation->notes;
                $modal_data->requiere_invoice = $reservation->requiere_invoice;

                // Of Stay
                $modal_data->is_express = $reservation->is_express;
                $modal_data->room_number = $reservation->room->room_name;
                $modal_data->room_type = $reservation->roomType->tr_name;
                $modal_data->regimen = $reservation->regimen->regimen_name;

                // Of Contract
                $modal_data->agency = $reservation?->agency?->agency_name;
                $modal_data->source = $reservation->source->source_name;

                // Of Payment
                $modal_data->suggested_price = $reservation->suggested_price;
                $modal_data->final_price = $reservation->final_price;
                $modal_data->lodging_contract = $reservation->lodging_contract;


            //* Control Data
            $modal_data->status = $reservation->Status->status_name;
            $modal_data->guest_status = $reservation->guestStatus->status_name;

            //* Saldos
            $modal_data->lodgingPayments = $lodgingPayments;
            $modal_data->extraPayments = $extraPayments;
            $modal_data->consumptionPayments = $consumptionPayments;

            //* Cargos
            $modal_data->extraCharges = $extraCharges;
            $modal_data->consumptionCharges = $consumptionCharges;
            $modal_data->total_price = $reservation->total_price;

            //* Saldos Pendientes
            $modal_data->lodgingPayment_left = number_format($lodgingPayment_left, 2, '.', '');
            $modal_data->extraPayment_left = number_format($extraPayment_left, 2, '.', '');
            $modal_data->consumptionPayment_left = number_format($consumptionPayment_left, 2, '.', '');

        return $modal_data;
    }

    public function getHotelIndicators(){
      //* Control Data
        // Time Controls
        $now = Carbon::now();
        $today = $now->format('Y-m-d');
        $time_window = 15;

        // Data to return
        $chartData = (object) [
          // Rooms Data
            "occupancy" => 0,       // % de Ocupación
            "roomsOnUse" => '',     // Habitaciones en Uso
            "totalRooms" => 0,      // Total de Habitaciones para Uso
            "roomsOccupancy" => 0,  // Habitaciones en Uso
            "blockedRooms" => '',   // Habitaciones Deshabilitadas

          // Arrives and Departures
            "totalArrives" => 0,    // Total de Llegadas de Hoy
            "totalDepartures" => 0, // Total de Salidas de Hoy

          // Guests
            "totalGuests" => 0,     // Huéspedes en el Hotel
        ];

        // Optimized Queries
        $rooms = Room::all();

        $roomsOnUse = [];
        $departures = [];
        $arrivals = [];

        $reservations = Reservation::where('status_id','!=',7) // Avoid Cancelled Reserves
            ->where(function ($query) use ($now, $time_window) { // Only analyze nearly reserves
                $query->whereBetween('date_entry', [
                    $now->copy()->subDays($time_window)->toDateString(),
                    $now->copy()->addDays($time_window)->toDateString()
                ])
                ->orWhereBetween('date_departure', [
                    $now->copy()->subDays($time_window)->toDateString(),
                    $now->copy()->addDays($time_window)->toDateString()
                ]);
            })->get();

      //* Compute Indicators
        //? Rooms Data
            /*Chart Data | Total Rooms*/ $chartData->totalRooms = $rooms->count();

          // Ignore Overbooked/Unassigned/Disabled Rooms
            foreach ($rooms as $room) {
                if(in_array($room->roomType->id, [1,2]))
                    $chartData->totalRooms -= 1;
            }

          // Occupied Rooms
            foreach ($reservations as $reservation){
              // Parse datetime
                $entryDateTime = Carbon::parse($reservation->date_entry . ' ' . $reservation->hour_entry);
                $departureDateTime = Carbon::parse($reservation->date_departure . ' ' . $reservation->hour_departure);

              // Support
                $status_id = $reservation->status['id'];
                $guest_status_id = $reservation->guestStatus['id'];

              // Pre-calc
                $oneDayLater = Carbon::parse($reservation->date_entry)->addDay()->format('Y-m-d');
                // $twoDaysLater =Carbon::parse($reservation->date_entry)->addDays(2)->format('Y-m-d');

              // Classify
                if ( //# Llegadas
                    (//? Normal Reservations (ignore hours completely)
                        !$reservation->is_express &&
                        (
                            ($today === $reservation->date_entry //* Day of Entry
                            && $guest_status_id === 3) // Ninguno
                            ||
                            ($today === $oneDayLater  //* After the First "No show"
                            && $guest_status_id === 5) // No se presenta
                            // ||
                            // ($today === $twoDaysLater
                            // && $reservation->show_in_calendar === 0  //* After the Second "No show"
                            // && $guest_status_id === 5) // No se presenta
                        )
                    ) ||
                    (//? Express Reservations (always use hours)
                        // Express también cuenta por día, no por hora
                        $reservation->is_express &&
                        $today === $reservation->date_entry &&
                        $guest_status_id === 3
                    )
                ) {
                    $arrivals[] = $reservation;
                }

                elseif ( //# Salidas
                    (//? Normal Reservations (ignore hours completely)
                        !$reservation->is_express &&
                        $reservation->date_departure <= $today &&
                        !in_array($guest_status_id, [6, 5]) && // [Check-out, No se presenta]
                        $status_id === 1 // Confirmado
                    )
                    ||
                    (//? Express Reservations (always use hours)
                        // Express: solo contar si ya terminó realmente
                        $reservation->is_express && $now >= $departureDateTime &&
                        !in_array($guest_status_id, [6, 5]) && // [Check-out, No se presenta]
                        $status_id === 1 // Confirmado
                    )
                ) {
                    $departures[] = $reservation;
                }

                if ( //# En el Hotel
                    (//? Normal Reservations (ignore hours completely)
                        !$reservation->is_express &&
                        $today >= $reservation->date_entry && $today < $reservation->date_departure &&
                        $guest_status_id == 4 && $status_id === 1 // Check-in && Confirmado
                    )
                    ||
                    (//? Express Reservations (always use hours)
                        // Express: siempre por hora real
                        $reservation->is_express &&
                        $now >= $entryDateTime && $now < $departureDateTime &&
                        $guest_status_id == 4 && $status_id === 1 // Check-in && Confirmado
                    )
                ) {
                    /*Chart Data | Total Guests*/ $chartData->totalGuests += $reservation->number_children + $reservation->number_adults;

                    if ((!in_array($reservation->room_id, $roomsOnUse, true)) && $reservation->roomType->id != 2)
                        $roomsOnUse[] = $reservation->room_id;
                }
            }

            /*Chart Data | Total Arrives*/ $chartData->totalArrives = count($arrivals);
            /*Chart Data | Total Departures*/ $chartData->totalDepartures = count($departures);

          // Rooms on Use
            if (!empty($roomsOnUse)) {
                foreach ($roomsOnUse as $i => $roomId) {

                    $roomData = Room::find($roomId);

                    $chartData->roomsOnUse .= $roomData->room_name;

                    if(($i+1) < count($roomsOnUse)){
                        $chartData->roomsOnUse .= ', ';
                    }
                }
            } else {
                $chartData->roomsOnUse = "#";
            }

          // Blocked Room
            $disabledRooms = Room::where('room_status', 'Desactivada')
                                ->orWhere('room_status', 'Bloqueada')->get();

            foreach ($disabledRooms as $i => $room) {
                /*Chart Data | Blocked Rooms */ $chartData->blockedRooms .= $room->room_name;

                if(($i+1) < count($disabledRooms))
                    $chartData->blockedRooms .= ', ';
            }

            if(!count($disabledRooms))
                $chartData->blockedRooms = 'Ninguna';

          // Occupancy
            /*Chart Data | Occupied Rooms */ $chartData->roomsOccupancy = count($roomsOnUse);

            try {
                $percentage = ($chartData->roomsOccupancy * 100) / $chartData->totalRooms;
            } catch (\Throwable $th) {
                $percentage = ($chartData->roomsOccupancy * 100) /1;
            }

            $percentage = number_format($percentage, 2, '.', '');
            /*Chart Data | Occupancy Percentage*/ $chartData->occupancy = floor($percentage);

        return json_encode($chartData);
    }

    // For Reservations Page
    public function getOverbooking(Request $request){
      //* Control Data
        // Request
        $has_control_hours = $request->boolean('has_control_hours');

        // Reserves to Analyze
        $reservations = Reservation::where([
            ['show_in_calendar', '!=', 0],
            ['status_id', '!=', 7], // Cancelled
        ])
        ->whereNotIn('guest_status_id', [5, 6]) // No Show & Checkout
        ->get();

        // Time window for analysis (15 days before and after today)
        $time_window = 15;
        $currentDate = Carbon::today();
        $fifteenDaysAgo = $currentDate->copy()->subDays($time_window);
        $fifteenDaysLater = $currentDate->copy()->addDays($time_window);

        // Working structures
        $currentReserves = []; // Reservations within the analysis window
        $sobreVentas = []; // Reservations involved in overbooking
        $mensajes = []; // Messages to return

      //* Helper: overlap validator
        $validateOverlap = function ($a, $b) use ($has_control_hours) {
            if ($has_control_hours) { // Consider times
                return (
                    $a->entry < $b->departure &&
                    $a->departure > $b->entry
                );
            } else { // Only use dates
                $a_start = $a->entry->copy()->startOfDay();
                $a_end   = $a->departure->copy()->startOfDay();

                $b_start = $b->entry->copy()->startOfDay();
                $b_end   = $b->departure->copy()->startOfDay();

                return ($a_start < $b_end && $a_end > $b_start);
            }
        };

      //* Filter Reserves
        // By time interval
        foreach ($reservations as $reserve) {
            // Obtain bookings that match the indicated time interval
            if (
                Carbon::parse($reserve->date_entry)->greaterThanOrEqualTo($fifteenDaysAgo) &&
                Carbon::parse($reserve->date_departure)->lessThanOrEqualTo($fifteenDaysLater) &&
                $reserve->roomType_id != 2 && // Exclude unassigned rooms
                $reserve->room // Ensure reservation has a room assigned
            ) {
              // Build reserve summary
                $data = new \stdClass;
                  // Basic Data & Room assignment
                    $data->id = $reserve->id;
                    $data->room = $reserve->room->id;
                    $data->room_name = $reserve->room->room_name;

                  // Datetime ranges (date + time)
                    $data->entry = Carbon::parse($reserve->date_entry . ' ' . $reserve->hour_entry);
                    $data->departure = Carbon::parse($reserve->date_departure . ' ' . $reserve->hour_departure);

                  // Other Controls
                    $data->is_express = $reserve->is_express;

                $currentReserves[] = $data;
            }
        }

        // Extract reservations sharing the same room in the indicated time interval
        foreach ($currentReserves as $key => $currentReserve) {
            foreach ($currentReserves as $i => $otherReserve) {

                // Skip compare same records and ensure both reservations belong to the same room
                if ($i !== $key && $otherReserve->room === $currentReserve->room) {

                    // Detect overlap
                    if ($validateOverlap($currentReserve, $otherReserve)) {
                        if (!in_array($currentReserve, $sobreVentas, true))
                            $sobreVentas[] = $currentReserve;
                    }
                }
            }
        }

        // Identify reservations that overlap within the same room
        $groupedByRoom = collect($currentReserves)->groupBy('room'); // Group to avoid unnecessary cross-room comparisons

        foreach ($groupedByRoom as $room_id => $reserves) {
            $reserves = $reserves->values(); // Reset indexes to allow numeric iteration

            foreach ($reserves as $key => $currentReserve) {
                foreach ($reserves as $i => $otherReserve) {

                    // Avoid comparing the same reservation against itself
                    if ($i !== $key) {
                        // Detect time overlap between two reservations
                        if ($validateOverlap($currentReserve, $otherReserve)) {
                            if (!in_array($currentReserve, $sobreVentas, true))
                                $sobreVentas[] = $currentReserve;
                        }
                    }
                }
            }
        }

        // Calculate exact overlapping ranges and generate messages
        $groupedSobreVentas = collect($sobreVentas)->groupBy('room'); // Group reservations already identified as overbookings

        foreach ($groupedSobreVentas as $room_id => $reserves) {
            $reserves = $reserves->values(); // Normalize indexes for iteration

            foreach ($reserves as $key => $mainReserve) {
                foreach ($reserves as $i => $secondaryReserve) {
                    if ($i === $key) continue; // Skip comparison with itself

                    // Validate overlap between reservations
                    if ($validateOverlap($mainReserve, $secondaryReserve)) {

                        // Calculate exact intersection interval between both reservations
                        $conflictStart = $mainReserve->entry->copy()->max($secondaryReserve->entry);
                        $conflictEnd   = $mainReserve->departure->copy()->min($secondaryReserve->departure);

                        // Generate message depending on reservation type
                        if ($mainReserve->is_express || $secondaryReserve->is_express) { // Express
                            $message = LangHelper::get('common_responses_and_messages.overbooking_message') . " " .
                                LangHelper::get('entities.hotel.room') ." #". $mainReserve->room_name
                                ."  (".$conflictStart->format('Y-m-d H:i')." - ".$conflictEnd->format('Y-m-d H:i').")";

                        } else { // Nights
                            $date_formatted = $has_control_hours
                                ? $conflictStart->format('Y-m-d H:i')
                                : $conflictStart->toDateString();

                            $message = LangHelper::get('common_responses_and_messages.overbooking_message') . " " .
                                LangHelper::get('entities.hotel.room') . " #" . $mainReserve->room_name
                                ."  (".$date_formatted.")";
                        }

                        // Avoid duplicate messages
                        if (!in_array($message, $mensajes)) $mensajes[] = $message;
                    }
                }
            }
        }

        return response()->json(mb_convert_encoding($mensajes, 'UTF-8', 'UTF-8'));
    }

    // For Edit Reservation
    public function checkPaymentAndCharges($id) {

        // Basic Data
        $reservation = Reservation::where('id' , $id)->first();

        // Payments and Charges
        $lodgingPayments = LodgingPayments::where('reservation_id',$id)->where('status', 'Activo')->sum('payment_price');
        $extraPayments = ExtraPayments::where('reservation_id',$id)->where('status', 'Activo')->sum('payment_price');
        $extraCharges = ExtraCharges::where('reservation_id',$id)->where('status', 'Activo')->sum('extras_price');
        $consumptionPayments = ConsumptionPayments::where('reservation_id',$id)->where('status', 'Activo')->sum('payment_price');
        $consumptionCharges = ConsumptionCharges::where('reservation_id',$id)->where('status', 'Activo')->sum('consumption_price');

        // Saldos Restantes
        $lodgingPayment_left = $reservation->total_price - $lodgingPayments;
        $extraPayment_left = $extraCharges - $extraPayments;
        $consumptionPayment_left = $consumptionCharges - $consumptionPayments;

        // Ajuste
        if ($lodgingPayment_left < 0) {
            $lodgingPayment_left = 0;
        }
        if ($extraPayment_left < 0) {
            $extraPayment_left = 0;
        }
        if ($consumptionPayment_left < 0) {
            $consumptionPayment_left = 0;
        }

        $data = new stdClass;
            $data->extraPayment_left = $extraPayment_left;
            $data->consumptionPayment_left = $consumptionPayment_left;
            $data->lodgingPayment_left = $lodgingPayment_left;

            $data->extras_contract = $reservation->extras_contract;
            $data->consumption_contract = $reservation->consumption_contract;
            $data->lodging_contract = $reservation->lodging_contract;

        return json_encode($data);
    }

}
