/* Constants */
  // Reserve Controls
    window.let_reserve_checkout = false;

  // Room Context
    window.minimum_stay = null;
    window.room_limit = null;

    window.last_pricing_context = {
        room_id: null,
        total_pax: null,
        is_express: null,
        selected_package: null,
        price: null
    };

  // Loader & Toasts
    window.tolerance_modal_shown = false;
    window.toast_duration = window.toast_duration || 4000;
    window.loader = window.loader || {
        show(text = translateAndReplace("common_responses_and_messages.loading")) {
            Swal.fire({
                title: text,
                html: '<p class="mt-2">' + translateAndReplace("common_responses_and_messages.please_wait") + '</p>',
                allowOutsideClick: false,
                allowEscapeKey: false,
                backdrop: true,
                didOpen: () => {
                    Swal.showLoading();
                }
            });
        },
        hide() {
            if (Swal.isVisible()) Swal.close();
        }
    };

/* General Controls */
$(document).ready(function () {
    // On close Reservation form
    $('#formModal').on('hide.bs.modal', function () {
        document.activeElement.blur();
    });
});

/* Window Observers */
    window.onbeforeunload = function () {
        localStorage.removeItem("assignedRoomType");
    };

/* Cargar Formulario */
    async function loadReserveForm(id) {

      // Set Action to buttons
        $('#add_lodgingP, #add_extraP, #add_consumptionP').val(translateAndReplace("entity_forms.reservation.register_payment"));
        $('#add_consumptionC, #add_extraC').val(translateAndReplace("common_actions.register"));

      // Reset Form
        $('#sample_form')[0].reset();

      // Define internal Control Status
        window.let_reserve_checkout = false;

      // Assigns action to Buttons
        $('#action').val("Reserve");
        $('#action_button').val(translateAndReplace("common_actions.update"));

      // Seed Data
        try {
            // Start Loader
            window.loader.show();

            // Get Reservation Data
            const reservationResponse = await $.getJSON(`/reservations/${id}/edit`);
            const reservationData = reservationResponse.data;

            // Draw all Statuses
            $('#estatus_id').html(config.data.statuses);
            $('#guest_estatus_id').html(config.data.guestStatuses);

            const could_be_cancelled = [3, 5, '3', '5'].includes(reservationData.guest_status_id);
            if (could_be_cancelled)
                $('#estatus_id').append(config.data.waitingCheckinStatuses);

            // Define available rooms
            const roomLoaded = await loadRooms(reservationData);

            // Get Client Data
            cleanClientData();
            const clientLoaded = await loadClient(reservationData.client_id);

            // Seed Data
            await assignReservationData(reservationData, clientLoaded);

            // Payments and Charges
            await loadReservationPaymentsAndCharges(id);

            // Check Tolerance Limit
            if(window.config.data.features.has_express_reservations && reservationData.is_express)
                debounce(() => checkToleranceLimit(reservationData), 900)();

        } catch (error) {
            // console.error("Error loading reservation data:", error);

            window.loader.hide(); // Close loader
            showToast (
                translateAndReplace("common_responses_and_messages.data_not_loaded"),
                "#E02424",
                "#C81E1E",
                "top",
                "right"
            );
        }

      // Support Functions
        async function loadRooms(data) {
          // Control Data
            const disabledBackground = "disabled-fields";
            const is_express = data.is_express;

          // Seed Control Fields
            $('#is_express_reserve').val(Number(is_express)).trigger('change');

          // Seed Room Fields
            if (data.roomType_id == 2) { // Unassigned
                // Define unique value
                const unassignedOption = `<option value="1" selected>${translateAndReplace("entity_forms.reservation.unassigned_room")}</option>`;

                // Custom Room Select
                $('#select-room')
                    .attr('readonly', true).prop('disabled', false).addClass(disabledBackground)
                    .html(unassignedOption);
                $('#roomLabel').addClass(disabledBackground);

                // Assign unassigned's prices
                ['#discount', '#precio_sugerido', '#precio_original_sugerido', '#precio_final', '#total', '#precio']
                    .forEach(id => $(id).val(0.00).addClass(disabledBackground).attr('readonly', true));

            } else if (data.roomType_id == 1) { // Overbooking
                // Get all rooms available for overbooking
                const roomList = await $.get(`/api/rooms/for-overbooking`, { is_express_reserve: is_express });

                // Define select structure
                const default_select = `<option value="" disabled selected>${translateAndReplace("entity_forms.reservation.select_room")}</option>`;
                const options = roomList.map(r => `<option value="${r.id}">${r.room_name}</option>`).join('');

                // Custom Room Select
                $('#select-room')
                    .attr('readonly', false).prop('disabled', false).removeClass(disabledBackground)
                    .html(default_select + options);
                $('#roomLabel').removeClass(disabledBackground);

            } else { // Normal Selection
                // Update available rooms for selected Room type
                const {available_rooms, packages} = await $.get(`/api/room-types/${data.roomType_id}/reservation/${data.id}/update-available-rooms`, {
                    from: `${data.date_entry} ${data.hour_entry}`,
                    to: `${data.date_departure} ${data.hour_departure}`,
                    has_control_hours: window.config.data.features.has_control_hours
                });

                // If there are no rooms available
                if (available_rooms.length === 0) {
                    // Define unique and disabled value
                    const notAvailable = `<option value="" disabled selected>${translateAndReplace("neutral_words.not_available")}</option>`;

                    // Custom Room Select & Package Duration
                    $('#select-room, #package_duration')
                        .attr('readonly', true).prop('disabled', true).addClass(disabledBackground)
                        .html(notAvailable);
                    $('#roomLabel').addClass(disabledBackground);

                    // Launch toastify message
                    showToast (
                        translateAndReplace("entity_forms.reservation.room_type_not_available"),
                        "#E02424", "#C81E1E"
                    );
                } else {
                  // Extract Package Duration
                    if (window.config.data.features.has_express_reservations && is_express) {
                        let package_options = ``;
                        packages.forEach(p => {
                            package_options += `<option value="${p}">${p} H</option>`;
                        });

                        // Custom Package Select
                        $('#package_duration')
                            .attr('readonly', false).prop('disabled', false).removeClass(disabledBackground)
                            .html(package_options).trigger('change').val(data.number_hours);
                    }

                  // Define room select structure
                    let room_options = `<option value="" disabled selected>${translateAndReplace("entity_forms.reservation.select_room")}</option>`;
                    available_rooms.forEach(r => {
                        const additional_properties = `
                            ${!is_express ? "" : `data-checkout-penalty="${r.express_checkout_penalty}"`}
                        `;

                        room_options += `<option value="${r.id}" ${additional_properties}>${r.room_name}</option>`;
                    });

                    // Custom Room Select
                    $('#select-room')
                        .attr('readonly', false).prop('disabled', false).removeClass(disabledBackground)
                        .html(room_options);
                    $('#roomLabel').removeClass(disabledBackground);
                }

                // Set assigned room value
                const exists = available_rooms.some(r => r.id == data.room_id);
                $('#select-room').val(exists ? data.room_id : "");
            }

            return true;
        }

        async function loadClient(clientId) {
            // Get Client data
            const response = await $.getJSON(`/clients/${clientId}/edit`);
            const client = response.data;

            // Define Identity Docs Structure
            await setClientIDStatus(client.identity_document_type); // Asíncrono

            return client;
        }

        async function assignReservationData(data, client) {
            // Assign Values
            $('#visual_folio').val(data.id);
            $('#estatus_id').val(data.status_id).trigger('change');
            $('#guest_estatus_id').val(data.guest_status_id);
            $('#agencia_id').val(data.agency_id);
            $('#fuentes_id').val(data.source_id);
            $('#reservation_date').val(data.reservation_date);
            $('#lodgingContract').val(data.lodging_contract).trigger("input");

            $('#datetime_ini').val(`${data.date_entry}T${data.hour_entry}`);
            $('#dateini').val(data.date_entry);
            $('#timeini').val(data.hour_entry);

            $('#datetime_fin').val(`${data.date_departure}T${data.hour_departure}`);
            $('#datefin').val(data.date_departure);
            $('#timefin').val(data.hour_departure);

            $('#reserva_noches').val(data.number_nights);
            $('#reserva_horas').val(data.number_hours);
            $('#regimen_id').val(data.regimen_id);
            $('#reserva_adultos').val(data.number_adults);
            $('#reserva_ninos').val(data.number_children);
            $('#count_children').prop('checked', Boolean(data.include_children_in_pax));
            $('#select-type').val(data.roomType_id);
            $('#select-room').val(data.room_id);
            $('#discount').val(data.discount_percentage);
            $('#precio_sugerido').val(data.suggested_price);
            $('#precio_original_sugerido').val(data.original_suggested_price ?? data.suggested_price);
            $('#precio_final').val(data.final_price);
            $('#total').val(data.total_price);
            $("#motivo_reserva").val(data.reservation_reason);
            $("#comentarios").val(data.notes);
            $('#solicitar_factura').prop('checked', Boolean(data.requiere_invoice)).trigger('change');
            $('#reference_invoice_uuid').val(data.invoice_uuid);
            $('#hidden_id').val(data.id);

            localStorage.setItem("assignedRoomType", data.roomType_id);
            updateRoomLimitManually();

            // Assign Client
            $("#clientSearchResults").hide();
            $("#client_id_section").show();
            $("#input-search-container").removeClass("mb-1");
            $("#search_client").val("");

            $('#client_id, #fake_client_id').val(client.id);
            $('#client_reference').val(client.client_name);
            $('#client_segment_type').val(client.customer_segment);
            $('#client_behavior_report').val(client.behavior_report);
            $('#client_phone').val(client.client_phone);
            $('#client_email').val(client.client_email);
            $('#client_state').val(client.client_state);
            $('#client_document_type').val(client.identity_document_type);
            $('#client_document_number').val(client.identity_document_number);
            toggleEditClientSection(true);

            // Get Charges and Payments
                // General
                $('#lodging_payment_reservation, #extra_charge_reservation, #extra_payment_reservation, #consumption_charge_reservation, #consumption_payment_reservation').val(data.id);

                // Lodging
                $('#tarifaSugerida').val(data.suggested_price);
                $('#tarifa').val(data.final_price);
                $('#tarifaTotal').val(data.total_price);
                $('#contratoHospedaje').val(data.lodging_contract);

                // Consumption
                $('#consumptionContract, #consumptionContract_2').val(data.consumption_contract);

                // Extras
                $('#extraContract, #extraContract_2').val(data.extras_contract);

            // Update interface
            $('#action_button').val(translateAndReplace('common_actions.update'));
            $('#action').val("Reserve");

            // Close loader
            $('#formModal').one('shown.bs.modal', function () {
                window.loader.hide();
            });

            // Open modal and Define Structure
            $('#formModal').modal('show');
            $('#defaultTab').tab('show');

            // Check Agency select Status
            if (data.source_id == 3)
                $('#agencia_id').attr('readonly', false).attr('disabled', false).removeClass("disabled-fields");
            else
                $('#agencia_id').attr('readonly', true).attr('disabled', true).addClass("disabled-fields");
        }
    }

/* Statuses Control */
    $(function () {
        $('#estatus_id').on('change', defineAssistanceControl);
    });

    function defineAssistanceControl() {
        var estatus_id = $(this).val();

        if (Number(estatus_id) === 7) {
            $('#guest_estatus_id').html(`<option value="3">${translateAndReplace("seeders.statuses.none")}</option>`);
        } else {
            $('#guest_estatus_id').html(config.data.guestStatuses);
        }
    }

/* Resources and Agencies Control */
    $(function () {
        $('#fuentes_id').on('input', onSelectSource);
    });

    function onSelectSource() {
        var source_id = $(this).val();

        if (source_id == 3) { // 3 is the ID of the source with the value 'Agencia'
            $('#agencia_id')
                .prop({ readonly: false, disabled: false })
                .removeClass("disabled-fields");
        } else {
            $('#agencia_id')
                .prop({ readonly: true, disabled: true }).prop('selectedIndex', 0)
                .addClass("disabled-fields");
        }

    }

/* Buscador de Clientes */
  //* Page Behavior
    // On Load
    $(function () {
        $('#search_client').on('input', debounce(onSearchClient, 300));
    });

    // Interactions
    $(document).on('click', function (event) {
        const target = $(event.target);

        if (!target.closest('.search-container').length) {
            $("#input-search-container").removeClass("mb-1");
            $('#clientSearchResults').hide();
            $('#search_client').val('');
        }
    });

  //* Function
    function debounce(func, delay) {
        let timeout;
        return function (...args) {
            const context = this;
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(context, args), delay);
        };
    }

    function onSearchClient() {
        const term = $(this).val();

        if (term.length <= 1) {
            $("#input-search-container").removeClass("mb-1");
            $('#clientSearchResults').empty().hide();
        }
        if (term.length > 1) {
            $.get(`/api/clients/search/${term}`, function (data) {
                if (data.length >= 1) {
                    const html_select = data.map(client => `
                        <button type="button" onclick="onSelectClient(${client.id})" class="py-2 list-group-item list-group-item-action">
                            <p class="mb-1 text-uppercase fw-normal">${client.client_name}</p>

                            <p class="text-reset mb-0" style="font-size:0.85rem">
                                ${
                                    client.client_email != translateAndReplace('neutral_words.none_2')
                                        ? `<span class="fw-normal">${translateAndReplace('entity_fields.common.email')}:</span> ${client.client_email} &nbsp;•&nbsp; `
                                        : ""
                                }
                                ${
                                    client.client_phone != translateAndReplace('neutral_words.none_2')
                                        ? `<span class="fw-normal">${translateAndReplace('entity_fields.common.phone')}:</span> ${client.client_phone}`
                                        : ""
                                }
                            </p>

                            ${ getFeatureStatus("identity_documents")
                                    ? `<small><span class="fw-normal">${translateAndReplace('entity_fields.client.document_number')}</span> ${client.identity_document_number}</small>`
                                    : ""
                            }
                        </button>
                    `).join('');

                    $('#clientSearchResults').html(html_select).show();
                    $("#input-search-container").addClass("mb-1");
                } else {
                    $('#clientSearchResults').html(`
                        <button type="button" class="py-1 list-group-item list-group-item-action pe-0" disabled>
                            Sin resultados
                        </button>
                    `).show();
                    $("#input-search-container").addClass("mb-1");
                }
            });
        }
    }

    async function onSelectClient(id) {
      // Clean Search Section
        $('#clientSearchResults').empty().hide();
        $("#input-search-container").removeClass("mb-1");

      // Request Client Data
        $.get(`/clients/${id}/edit`, async function (data) {
          // Control Data
            const client = data.data;

          // Check Client's Behavior
            let allow_render = true;
                if (client.behavior_risk_score >= 40) allow_render = await warnClientBehavior(client);

          // Fill Fields
            if (!allow_render) return;
            cleanClientData(); // Clean Client's Section

            $('#client_id, #fake_client_id').val(client.id);
            $('#client_reference').val(client.client_name);
            $('#client_segment_type').val(client.customer_segment);
            $('#client_behavior_report').val(client.behavior_report);
            $('#client_phone').val(client.client_phone);
            $('#client_email').val(client.client_email);
            $('#client_state').val(client.client_state);

            $('#client_document_type').val(client.identity_document_type);
                await setClientIDStatus(client.identity_document_type);
            $('#client_document_number').val(client.identity_document_number);

            $('#discount').val(client.discount_per_loyalty);

          // Display Sections
            $('#client_id_section, #clean_chose_client_data').show();

          // Secondary Processes
            // Allow Edit Data
            toggleEditClientSection(true);
        });
    }

    function defineClientInputRestrictions() {
        // Extract Values from Fields
        const client_id = $('#client_id').val();
        const fake_client_id = $('#fake_client_id').val();

        // Control variables
        const client_already_assigned = ![null, ""].includes(client_id) && ![null, ""].includes(fake_client_id);

        // Enable Buttons
        $('#clean_chose_client_data').toggle(client_already_assigned);

        // Customize fields
        $('#client_reference, #client_phone, #client_email, #client_state, #client_document_type, #client_document_number')
            .prop({ readonly: client_already_assigned })
            .toggleClass('disabled-fields', client_already_assigned)

        $('#client_document_type, #client_segment_type, #client_behavior_report')
            .toggleClass('disabled-fields', client_already_assigned)
            .css({
                'pointer-events': client_already_assigned ? 'none' : 'auto',
            })
            .attr({
                'readonly': client_already_assigned,
                'tabindex': client_already_assigned ? '-1' : null
            });

        if (!client_already_assigned)
            setClientIDStatus( $("#client_document_type").val() );
    }

    async function warnClientBehavior(client_data) {
      // Display Swal
        const result = await Swal.fire({
            icon: 'warning',
            title: translateAndReplace('common_responses_and_messages.warning'),
            html: `
                ${translateAndReplace('entity_forms.reservation.behavior_warning',
                    {
                        name: client_data.client_name,
                        report: translateAndReplace(`enums.hotel.clients.behavior_report.${client_data.behavior_report}`),
                        color: client_data.behavior_risk_color,
                        risk: client_data.behavior_risk_level_label,
                    }
                )}<br><br>

                ${translateAndReplace('entity_forms.reservation.behavior_confirmation')}
            `,
            allowOutsideClick: false,

            confirmButtonText: translateAndReplace('common_actions.accept'),
            confirmButtonColor: "#0D6889",

            showCancelButton: true,
            cancelButtonText: translateAndReplace('common_actions.cancel'),
        });

      // Return Response
        return result.isConfirmed;
    }

    // Button Functions
    function cleanClientData(show_modal = false) {
        // Toggle Sections and Buttons
        $('#client_id_section, #clean_chose_client_data, #searchbar_section, #hide_searchbar_button').hide();
        $("#show_searchbar_button").show();

        // Reset Fields
        $('#client_id, #fake_client_id, #client_reference, #client_phone, #client_email, #client_state').val("");
        $('#client_segment_type').val("occasional");
        $('#client_document_type, #client_behavior_report').val("none").trigger('input');

        // Define Fields restrictions
        setTimeout(() => defineClientInputRestrictions(), 350);
        toggleEditClientSection(false);

        // Show Control Message
        if (show_modal) {
            Swal.fire({
                icon: 'info',
                title: translateAndReplace("entity_forms.reservation.disconnected_client_title"),
                confirmButtonText: translateAndReplace("common_responses_and_messages.ok"),
                html: `
                    <div class="container mb-0 pb-0 text-justify">
                        <p class="px-2">
                            ${translateAndReplace("entity_forms.reservation.disconnected_client_message")}
                        </p>
                        <ul class="text-left" style="font-size: 95%; color: #555;">
                            <li class="my-2"> ${translateAndReplace("entity_forms.reservation.disconnected_client_option_1")} </li>
                            <li class="my-2"> ${translateAndReplace("entity_forms.reservation.disconnected_client_option_2")} </li>
                        </ul>
                    </div>
                    `,
            });
        }
    }

    function showSearchBar() {
        $("#searchbar_section, #hide_searchbar_button").show();
        $("#show_searchbar_button").hide();
        $('#search_client').val('');
    }

    function hideSearchBar() {
        $("#searchbar_section, #hide_searchbar_button").hide();
        $("#show_searchbar_button").show();
        $('#search_client').val('');
    }

    function editClientData() {
      // Control Values
        const $client_document_number = $('#client_document_number');

      // Toggle Section
        toggleEditClientSection(false);

      // Backup Values
        const document_number = $client_document_number.val();

      // Enable Fields
        // Customize fields
        $('#client_reference, #client_phone, #client_email, #client_state, #client_document_type, #client_document_number')
            .prop({ readonly: false }).removeClass('disabled-fields');

        $('#client_document_type, #client_segment_type, #client_behavior_report')
            .removeClass('disabled-fields')
            .css({'pointer-events': 'auto'})
            .attr({'readonly': false, 'tabindex': null});

        // Define Document Management
        setClientIDStatus( $("#client_document_type").val() );
        $client_document_number.val(document_number);
    }

    function toggleEditClientSection(show_section) {
        $('#client-data-block').toggleClass("w-90", show_section);
        $('#client-secondary-actions').toggleClass("d-flex", show_section).toggle(show_section);
    }

/* Identity Document Control */
    $(function () {
        $('#client_document_type').on('input', function () {
            setClientIDStatus(this.value);
        });

        $('#client_document_number').on('change', debounce(defineExpressReference, 900));
    });

    function setClientIDStatus(document_type) {
        if (document_type == "none") {
            $('#client_document_number')
                .val("--- --- ---")
                .prop('readonly', true).prop('required', false)
                .addClass("disabled-fields");
        } else {
            $('#client_document_number')
                .val("")
                .prop('readonly', false).prop('required', true)
                .removeClass("disabled-fields");
        }
    }

    function defineExpressReference() {
        if(!window.config.data.features.has_express_reservations) return; // ONly works on Express Reservations

      // Abort if name is already assigned
        const $client_name_field = $('#client_reference');
            if(!['', null, undefined].includes($client_name_field.val().trim())) return;

        $client_name_field.val($('#client_document_number').val());
    }


/* Express Manage */
    // Triggers
    $(function () {
      // Triggers
        $('#is_express_reserve').on('change', toggleReservationType);
        $('#package_duration').on('change', setExpressDate);
    });

    function toggleReservationType() {
        const is_express = Boolean(Number($(this).val()));

        // Toggle Classes
        $('#datefin, #timefin').prop({ readonly: is_express }).toggleClass('disabled-fields', is_express)

        // Dynamic Value
        const current_date = moment();
        const checkin_date = current_date.format('YYYY-MM-DD');
        const checkout_date = current_date.clone().add(1, is_express ? 'hour' : 'day').format('YYYY-MM-DD');

        const checkin_time = is_express ? current_date.format('HH:mm') : "13:00";
        const checkout_time = is_express ? current_date.clone().add(1, 'hour').format('HH:mm') : "12:00";

          // Sample Dates and Times
            $('#dateini').val(checkin_date);
            $('#datefin').val(checkout_date);

            $('#timeini').val(checkin_time);
            $('#timefin').val(checkout_time);

          // Timestamps
            $('#datetime_ini').val(`${checkin_date}T${checkin_time}`);
            $('#datetime_fin').val(`${checkout_date}T${checkout_time}`);

          // Counters
            $('#reserva_noches').val(is_express ? 0 : 1);
            $('#reserva_horas').val(is_express ? 1 : 0);

          // Selects
            // Room Types
            const room_types = `
                <option value="" selected disabled>${translateAndReplace('entity_forms.reservation.select_room_type')}</option>
                ${is_express ? window.config.data.expressRoomTypes : window.config.data.normalRoomTypes}
            `
            $('#select-type').html(room_types);

            // Rooms & Packages
            $('#roomLabel').addClass("disabled-fields");
            $('#package_duration, #select-room')
                .attr('readonly', true).prop('disabled', true).addClass("disabled-fields")
                .html(`<option value="" disabled selected>-- -- --</option>`);

        // Dynamic Seections
        $('#package_duration_block').toggle(is_express);
        $('#reservation_total_block').toggle(!is_express);

        $('#selectedRateLabel').text(`${translateAndReplace(`entity_forms.reservation.${is_express ? "total_rate" : "rate"}`)}*`);
    }

    function setExpressDate({is_input_trigger = true} = {}) {
      // Control Data
        // Default
        const package_duration = is_input_trigger
            ? $(this).val()
            : $('#package_duration').val();

        if (!package_duration) return;

        // Builded
        const $checkin_date = $('#dateini');
        const $checkin_time = $('#timeini');
        const pointer_date = moment(`${$checkin_date.val()} ${$checkin_time.val()}`);

      // Build Periods
        const checkin_date = pointer_date.format('YYYY-MM-DD');
        const checkout_date = pointer_date.clone().add(package_duration, 'hour').format('YYYY-MM-DD');

        const checkin_time = pointer_date.format('HH:mm');
        const checkout_time = pointer_date.clone().add(package_duration, 'hour').format('HH:mm');

          // Sample Dates and Times
            $checkin_date.val(checkin_date);
            $('#datefin').val(checkout_date);

            $checkin_time.val(checkin_time);
            $('#timefin').val(checkout_time);

          // Timestamps
            $('#datetime_ini').val(`${checkin_date}T${checkin_time}`);
            $('#datetime_fin').val(`${checkout_date}T${checkout_time}`);

          // Counters
            $('#reserva_horas').val(package_duration);

      // Secondary Triggers
        $('#select-room').trigger('change');
    }

    function checkToleranceLimit(reservation_data) {
      // Avoid Multiple Launches
        if (window.tolerance_modal_shown) return;

      // Control Data
        // Times
        const now = moment();
        const checkout_with_tolerance = moment(// Parse Object
            `${reservation_data.date_departure} ${reservation_data.hour_departure}`, "YYYY-MM-DD HH:mm:ss"
        ).add( // Add Tolerance
            window.config.data.parameters.express_tolerance_minutes, 'minutes'
        );

        // Rooms
        const checkout_penalty = parseFloat(
            $('#select-room option:selected').data('checkout-penalty')
        );

        // Charges
        const extra_charge_concept = `(EC) ${translateAndReplace('entity_forms.reservation.checkout_penalty_title')}`;

        const penalty_charge_recorded = (r, penalty) => {
            return r.extra_charges?.find(charge => {
                return (
                    charge.status === "Activo" &&
                    (
                        charge.extras_concept === extra_charge_concept ||
                        charge.extras_concept.includes('(EC)')
                    ) &&
                    parseFloat(charge.extras_price) === penalty
                );
            });
        };

      // Validate Limit
        if (
            Boolean(reservation_data.is_express) // Is Express Reserve
            && parseInt(reservation_data.guest_status_id) === 4 // Status: Check-in
            && now.isAfter(checkout_with_tolerance) // Tolerance limit has been reached
            && !isNaN(checkout_penalty) // Room has checkout penalty defined
            && checkout_penalty > 0.00  // Room has checkout penalty to apply
            && penalty_charge_recorded(reservation_data, checkout_penalty) === undefined // Extra Charge hasn't been already applied
        ) {
          // Avoid to launch another modal
            window.tolerance_modal_shown = true;

          // Launch Modal
            Swal.fire({
                icon: 'warning',
                title: translateAndReplace('entity_forms.reservation.checkout_penalty_title'),
                html: `
                    <p>
                        ${translateAndReplace('entity_forms.reservation.checkout_penalty_description', {client: reservation_data.client_reference})}
                        <br><br>
                        ${translateAndReplace('entity_forms.reservation.checkout_penalty_message')}
                    </p>
                `,
                allowOutsideClick: false,

                confirmButtonText: translateAndReplace('entity_forms.reservation.apply_illusionary_checkout_penalty'),
                confirmButtonColor: "#0D6889",

                showDenyButton: true,
                denyButtonText: translateAndReplace('entity_forms.reservation.apply_checkout_penalty'),
                denyButtonColor: "#057A55",

                showCancelButton: true,
                cancelButtonText: translateAndReplace('common_actions.cancel'),
            }).then((result) => {
                window.tolerance_modal_shown = false;

                /*** Swal Results
                 * Confirm: {"isConfirmed": true, "isDenied": false, "isDismissed": false, "value": true}
                 * Deny:    {"isConfirmed": false, "isDenied": true, "isDismissed": false, "value": false}
                 * Cancel:  {"isConfirmed": false, "isDenied": false, "isDismissed": true, "dismiss": "cancel"}
                 */

                // Confirm: Apply Charge to Suggested Rate
                if (result.isConfirmed && !result.isDenied && !result.isDismissed && result.value) {
                  // Recompute Room Price
                    onSelectRoomChange({is_input_trigger: false, apply_checkout_penalty: true})

                  // Notify Update
                    showToast (
                        translateAndReplace("entity_forms.reservation.adjusted_express_rate"),
                        "#3E87A1", "#0D6889"
                    );
                }

                // Deny: Apply Charge as Extra Charge
                if (!result.isConfirmed && result.isDenied && !result.isDismissed && !result.value) {
                  // Add Extra charge
                    $.ajax({
                        url: config.routes.extraCharge,
                        method: "POST",
                        headers: {
                            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                        },
                        data: {
                            extra_charge_id: null,
                            extra_charge_reservation: reservation_data.id,
                            extra_charges_receptionist: window.config.data.receptionist,
                            extra_charge_date: moment().format('YYYY-MM-DD'),
                            extra_charge_concept,
                            extra_charge_amount: parseFloat(checkout_penalty)
                        },
                        dataType: "json",
                        success: function () {
                            showToast (
                                translateAndReplace("common_responses_and_messages.created_successfully"),
                                "#057A55", "#046C4E"
                            );

                            loadExtraData(reservation_data.id);
                        }
                    });
                }
            });
        }

        return;
    }

/* Buscar Habitación */
    // Specific constants
    window.respectRoomLimitDebounced = (window.respectRoomLimitDebounced || debounce(respectRoomLimit, 1600));
    window.selectRoomDebounced = window.selectRoomDebounced
        || debounce((check_child_counting = false) => {
            if (check_child_counting) {
                if ($('#count_children').prop('checked'))
                    onSelectRoomChange({ is_input_trigger: false });
            } else {
                onSelectRoomChange({ is_input_trigger: false });
            }
        }, 800);

    $(function () {
      // Triggers
        $('#select-type').on('change', onSelectTypeChange);
        $('#select-room').on('change', onSelectRoomChange);
    });

    async function onSelectTypeChange() {
        // Control Data
        const room_type_id = $(this).val();
        const room_id = $('#select-room').val();
        const is_express = Boolean(Number($('#is_express_reserve').val()));

        const entry_datetime = `${$('#dateini').val()} ${$('#timeini').val()}`;
        const departure_datetime = `${$('#datefin').val()} ${$('#timefin').val()}`;

        const disabledBackground = "disabled-fields";

        // Save Room Limit
        const selected_option = this.options[this.selectedIndex];
        const limit = selected_option.getAttribute('data-limit');
        const minimum_stay = selected_option.getAttribute('data-minimum-stay');

        window.minimum_stay = minimum_stay ? parseInt(minimum_stay) : null;
        window.room_limit = limit ? parseInt(limit) : null;

        // Define Available Rooms
        if (!room_type_id) {
            $('#select-room').html(`<option value="" disabled selected>${translateAndReplace("entity_forms.reservation.select_room")}</option>`);
            $('#package_duration').html(`<option value="" disabled selected>${translateAndReplace("entity_forms.reservation.select_package")}</option>`);
        }

        if (room_type_id == 2) {  // Unassigned  Type
            setTimeout(function() {
                // Define unique value
                const unassignedOption = `<option value="1" selected>${translateAndReplace("entity_forms.reservation.unassigned_room")}</option>`;

                // Custom Room Select
                $('#select-room')
                    .attr('readonly', true).prop('disabled', false).addClass(disabledBackground)
                    .html(unassignedOption);
                $('#roomLabel').addClass(disabledBackground);

                // Assign unassigned's prices
                [ '#discount', '#precio_sugerido', '#precio_original_sugerido', '#precio_final', '#total', '#precio' ]
                    .forEach(id => $(id).val(0.00).addClass(disabledBackground).attr('readonly', true));
            }, 500);

        } else if (room_type_id == 1) { // Overbooking
            // Get all rooms available for overbooking
            const roomList = await $.get(`/api/rooms/for-overbooking`, { is_express_reserve: is_express });

            // Define select structure
            const default_select = `<option value="" disabled selected>${translateAndReplace("entity_forms.reservation.select_room")}</option>`;
            const options = roomList.map(r => `<option value="${r.id}">${r.room_name}</option>`).join('');

            // Custom Room Select
            $('#select-room')
                .attr('readonly', false).prop('disabled', false).removeClass(disabledBackground)
                .html(default_select + options)
                .val(room_id);
            $('#roomLabel').removeClass(disabledBackground);

        } else { // Normal Selection
            const current_reservation_id = $('#hidden_id').val();
            const is_same_room_type = await localStorage.getItem("assignedRoomType") === room_type_id;

            // Update available rooms for selected Room type
            const {available_rooms, packages} = await $.get(`/api/room-types/${room_type_id}/reservation/${current_reservation_id}/update-available-rooms`, {
                from: entry_datetime,
                to: departure_datetime,
                includeActualRoom: is_same_room_type,
                has_control_hours: window.config.data.features.has_control_hours
            });

            // If there are no rooms available
            if (available_rooms.length === 0) {
                const notAvailable = `<option value="" disabled selected>${translateAndReplace("neutral_words.not_available")}</option>`;

                // Custom Room Select & Package Duration
                $('#select-room, #package_duration')
                    .attr('readonly', true).prop('disabled', true).addClass(disabledBackground)
                    .html(notAvailable)
                    .val(room_id);
                $('#roomLabel').addClass(disabledBackground);

                // Launch toastify message
                if (room_type_id)
                    showToast (
                        translateAndReplace("entity_forms.reservation.room_type_not_available"),
                        "#E02424",
                        "#C81E1E"
                    );

            } else {
              // Extract Package Duration
                if (window.config.data.features.has_express_reservations && is_express) {
                    let package_options = ``;
                    packages.forEach(p => {
                        package_options += `<option value="${p}">${p} H</option>`;
                    });

                    // Custom Package Select
                    $('#package_duration')
                        .attr('readonly', false).prop('disabled', false).removeClass(disabledBackground)
                        .html(package_options).trigger('change');
                }

              // Define room select structure
                let room_options = `<option value="" disabled selected>${translateAndReplace("entity_forms.reservation.select_room")}</option>`;
                available_rooms.forEach(r => {
                    const additional_properties = `
                        ${!is_express ? "" : `data-checkout-penalty="${r.express_checkout_penalty}"`}
                    `;

                    room_options += `<option value="${r.id}" ${additional_properties}>${r.room_name}</option>`;
                });

                // Custom Room Select
                const exists = available_rooms.some(r => r.id == room_id);

                $('#select-room')
                    .attr('readonly', false).prop('disabled', false).removeClass(disabledBackground)
                    .html(room_options);

                if (exists) $('#select-room').val(room_id);
                else $('#select-room').val("");

                $('#roomLabel').removeClass(disabledBackground);
            }

            return;
        }

        // Ensure room limit will be respected.
        respectRoomLimitDebounced();
    }

    async function onSelectRoomChange({is_input_trigger = true, apply_checkout_penalty = false} = {}) {
      // Ensure room has been selected
        const room_id = is_input_trigger
            ? $(this).val()
            : $('#select-room').val();
        if (!room_id) return;

      // Control Data
        // Parsed Data
        const date_entry = $('#dateini').val();
        const hour_entry = $('#timeini').val();

        const date_departure = $('#datefin').val();
        const hour_departure = $('#timefin').val();

        const number_adults = parseInt($('#reserva_adultos').val());
        const number_children = parseInt($('#reserva_ninos').val());
        const count_children = $('#count_children').prop('checked');
        const has_pax_pricing = window.config.data.features.has_pax_pricing;
        const has_additional_pax_charge = window.config.data.features.has_additional_pax_charge;

        const has_express_reservations = window.config.data.features.has_express_reservations;
        const is_express  = Boolean(Number($('#is_express_reserve').val()));
        const selected_package  = $('#package_duration').val();

        // Request Data
        const request = {
          // Period
            from: date_entry,
            to: date_departure,

          // Pax Status
            count_children,
            has_pax_pricing,
            has_additional_pax_charge,

            adults: number_adults,
            children: number_children,
            room_limit: window.room_limit,

          // Express Status
            has_express_reservations,
            is_express,
            hour_entry,
            hour_departure,
            selected_package,
            minimum_stay: window.minimum_stay,
            apply_checkout_penalty,
        };

        // Pricing Context
        const total_pax = count_children
            ? number_adults + number_children
            : number_adults;

        const currentContext = { room_id, total_pax, is_express, selected_package };

      // Get Room Price
        const data = await $.get(`/api/rooms/${room_id}/price`, request);

        // Concordance Messages
            if(!data.has_season){ // If there is no season in progress
                showToast (
                    translateAndReplace("entity_forms.reservation.adjusted_rate"),
                    "#3E87A1", "#0D6889"
                );
            }

            if(data.is_between_season){ // If stay is between two or more seasons
                showToast (
                    translateAndReplace("entity_forms.reservation.adjusted_rate_by_season"),
                    "#057A55", "#046C4E"
                );
            }

        // Identify pricing context changes
            const room_price = parseFloat( data.room_price.replace(/,/g, '') );

            const has_price_changed = window.last_pricing_context?.price !== room_price;
            const pax_changed = window.last_pricing_context?.total_pax !== total_pax;
            const room_changed = window.last_pricing_context?.room_id !== room_id;
            const package_changed = window.last_pricing_context?.selected_package !== selected_package;

        // Trigger notifications only if the rate changes
            if (has_price_changed) {
              // Express + Pax
                if (is_express && has_pax_pricing && (pax_changed || package_changed || room_changed)) {
                    showToast (
                        translateAndReplace("entity_forms.reservation.adjusted_express_pax_rate"),
                        "#057A55", "#046C4E"
                    );
                }

              // Express Simple
                else if (is_express && (package_changed || room_changed)) {
                    showToast (
                        translateAndReplace("entity_forms.reservation.adjusted_express_rate"),
                        "#3E87A1", "#0D6889"
                    );
                }

              // PAX
                else if ((has_pax_pricing || has_additional_pax_charge) && (pax_changed || room_changed)) {
                    showToast (
                        translateAndReplace("entity_forms.reservation.adjusted_pax_rate"),
                        "#057A55", "#046C4E"
                    );
                }

              // Seasonal
                else {
                    showToast (
                        translateAndReplace("entity_forms.reservation.adjusted_rate"),
                        "#3E87A1", "#0D6889"
                    );
                }
            }

        // Update Pricing Context
            await handlePricingContextUpdate({
                data, currentContext,
                room_id, total_pax, is_express, selected_package,
                is_input_trigger, has_pax_pricing, has_additional_pax_charge,
            });

      // Check Entry & Cleaning Time
        if (getFeatureStatus("control_hours")) {
            const cleaning_response = await $.get(
                `/rooms/${room_id}/check-entry-and-cleaning-time`,
                { entry_date: date_entry, entry_hour: hour_entry }
            );

            if (cleaning_response.show_modal) {
                await Swal.fire({
                    title: translateAndReplace("common_responses_and_messages.warning"),
                    icon: 'warning',
                    html: cleaning_response.message,
                    confirmButtonText: translateAndReplace("common_responses_and_messages.ok"),
                });
            }
        }

        // Ensure room limit will be respected.
        if (is_input_trigger) respectRoomLimitDebounced();
    }

    function setRoomPriceContext(roomContext, room_price = 0.0) {
      // Update pricing context
        window.last_pricing_context = { ...roomContext, price: room_price };

      // Assign Price to Room
        $('#precio_sugerido, #precio_original_sugerido').val(room_price.toFixed(2));
        $('#precio_sugerido').addClass("disabled-fields");

      // Re-Calculate Discount
        setTimeout(calculateDiscount(), 500);

      // Unlock Fields
        $('#discount, #precio_final, #total, #precio')
            .removeClass("disabled-fields")
            .attr('readonly', false);
    }

    async function handlePricingContextUpdate({
        data, currentContext,
        room_id, total_pax, is_express, selected_package,
        is_input_trigger, has_pax_pricing, has_additional_pax_charge,
    }) {
      // Identify pricing context changes
        const room_price = parseFloat(data.room_price.replace(/,/g, ''));
        const has_price_changed = window.last_pricing_context?.price !== room_price;
        const pax_changed = window.last_pricing_context?.total_pax !== total_pax;
        const room_changed = window.last_pricing_context?.room_id !== room_id;
        const package_changed = window.last_pricing_context?.selected_package !== selected_package;

      // Trigger notifications only if the rate changes
        if (has_price_changed) {
          // Express + Pax
            if (
                is_express && has_pax_pricing &&
                (pax_changed || package_changed || room_changed)
            ) {
                showToast(
                    translateAndReplace(
                        "entity_forms.reservation.adjusted_express_pax_rate"
                    ),
                    "#057A55", "#046C4E"
                );
            }

          // Express Simple
            else if (
                is_express && (package_changed || room_changed)
            ) {
                showToast(
                    translateAndReplace(
                        "entity_forms.reservation.adjusted_express_rate"
                    ),
                    "#3E87A1", "#0D6889"
                );
            }

          // PAX
            else if (
                (has_pax_pricing || has_additional_pax_charge) &&
                (pax_changed || room_changed)
            ) {
                showToast(
                    translateAndReplace(
                        "entity_forms.reservation.adjusted_pax_rate"
                    ),
                    "#057A55", "#046C4E"
                );
            }

          // Seasonal
            else {
                showToast(
                    translateAndReplace(
                        "entity_forms.reservation.adjusted_rate"
                    ),
                    "#3E87A1", "#0D6889"
                );
            }
        }

      // Update Pricing Context
        // Use returned Price, even if breakdown is necessary
          // Just in case user, don't want to interact with breakdown modal and prefers returned price
        setRoomPriceContext(currentContext, room_price);

      // Pricing Breakdown Control
        const price_breakdown = data.price_breakdown || [];

        if (data.display_breakdown && is_input_trigger) { // Display breakdown

          // Validation Modal
            const average_rate = await Swal.fire({
                icon: 'info',
                html: `
                    <div class="text-left px-4">
                        <p>
                            ${translateAndReplace('entity_forms.reservation.adjacent_rates_title')}
                        </p>

                        <p><b>
                            ${translateAndReplace('entity_forms.reservation.adjacent_rates_question')}
                        </b></p>

                        <ul class="text-left">
                            <li class="pb-3">
                                <b style="color: #057A55">
                                    ${translateAndReplace('common_actions.accept')}:
                                </b>
                                ${translateAndReplace('entity_forms.reservation.adjacent_rates_average_action')}
                            </li>

                            <li class="pb-3">
                                <b style="color: #0D6889">
                                    ${translateAndReplace('common_actions.edit')}:
                                </b>
                                ${translateAndReplace('entity_forms.reservation.adjacent_rates_edit_action')}
                            </li>
                        </ul>
                    </div>
                `,

                showCancelButton: false,
                allowOutsideClick: false,

                confirmButtonText: `${translateAndReplace('common_actions.deny')} ${translateAndReplace('common_actions.edit')}`,
                confirmButtonColor: "#0D6889",

                showDenyButton: true,
                denyButtonColor: "#057A55",
                denyButtonText: `${translateAndReplace('common_actions.approve')} ${translateAndReplace('common_actions.accept')}`,
            });

          // Manual Breakdown
            if (average_rate.isConfirmed) {
              // Build season rows
                const rows = price_breakdown.map((season, index) => {
                    const subtotal = season.price * season.days;

                    return `
                        <tr class="text-dark">
                            <td class="text-uppercase fw-semi-bold">
                                ${season.season_name}
                            </td>

                            <td>
                                ${formatCurrency(season.price, { decimals: 2 })}
                            </td>

                            <td>${season.days}</td>

                            <td style="width: 180px;">
                                <input type="number" step="0.1" min="0"
                                    data-index="${index}" data-days="${season.days}"
                                    class="form-control breakdown-price-input"
                                    style="pointer-events: auto;"
                                    value="${parseFloat(season.price).toFixed(1)}"
                                >
                            </td>

                            <td class="fw-normal">
                                <span id="season-total-${index}"
                                    class="season-total"
                                >
                                    ${formatCurrency(subtotal, {
                                        decimals: 2
                                    })}
                                </span>
                            </td>
                        </tr>
                    `;
                }).join('');

              // Set default Total
                const initial_total = price_breakdown.reduce(
                    (acc, season) => { return acc + (season.price * season.days); },
                    0
                );

              // Display Modal
                await Swal.fire({
                    width: 1000,
                    backdrop: true,
                    heightAuto: false,
                    scrollbarPadding: false,

                    title: `<div class="harsi-color pt-3">
                        ${translateAndReplace('entity_forms.reservation.average_rates_title')}
                    </div>`,

                    html: `
                        <div class="text-left px-5 mt-2">

                            <!- Instructions -->
                            <p class="mb-4 text-center text-dark">
                                ${translateAndReplace('entity_forms.reservation.average_rates_instructions')}
                            </p>

                            <!- Breakdown Table -->
                            <table class="table table-bordered">
                                <thead><tr class="text-center">
                                    <th>${translateAndReplace('entities.hotel.season')}</th>
                                    <th>${translateAndReplace('entity_forms.room.base_rate')}</th>
                                    <th>${translateAndReplace('entity_fields.common.days')}</th>
                                    <th>${translateAndReplace('entity_forms.reservation.amount_due')}</th>
                                    <th>Total</th>
                                </tr></thead>

                                <tbody>${rows}</tbody>
                            </table>

                            <!- Total Summary -->
                            <div class="row mt-3">
                                <div class="col-md-4 offset-md-8">
                                    <label for="breakdown-grand-total" class="fw-semi-bold external-label pb-1">
                                        ${translateAndReplace('ballots.normal.total')}
                                    </label>

                                    <input type="number" id="breakdown-grand-total" readonly disabled
                                        value="${initial_total.toFixed(1)}"
                                        class="form-control"
                                    >
                                </div>
                            </div>

                        </div>
                    `,

                    allowOutsideClick: false,
                    focusConfirm: false,

                    confirmButtonColor: "#0D6889",
                    confirmButtonText: translateAndReplace('common_actions.apply'),

                    showCancelButton: true,
                    cancelButtonText: translateAndReplace('common_actions.cancel'),

                    didOpen: () => {
                      // Center focus on Swal
                        $(document).off('focusin.modal');

                      // Recalculate totals dynamically
                        $('.breakdown-price-input').on('change', function () {
                            let grand_total = 0;

                            // Add up the totals for each season
                            $('.breakdown-price-input').each(function () {
                                const input = $(this); // Extract input element

                                const index = input.data('index'); // Index
                                const days = parseFloat(input.data('days')); // Days quantity
                                const value = parseFloat(input.val()) || 0; // Tarifa seleccionada

                                const subtotal = value * days; // Compute season rate
                                $(`#season-total-${index}`).text(`$${subtotal.toFixed(1)}`); // Assign rate to season wor

                                grand_total += subtotal; // Increment total rate
                            });

                            $('#breakdown-grand-total').val(grand_total.toFixed(1)); // Set new total
                        });
                    }

                }).then((result) => {
                    if (result.isConfirmed) {
                      // Extract Form Results
                        /* [{
                            season: "Tarifa Regular",
                            days: 3,
                            original_price: 100,
                            custom_price: 200,
                        }] */
                        const custom_breakdown = []; // Desglose final de asignación
                        const new_total_rate = $('#breakdown-grand-total').val();

                      // Build Breakdown updated
                        $('.breakdown-price-input').each(function () {
                            const input = $(this);
                            const index = input.data('index');

                            custom_breakdown.push({
                                season: price_breakdown[index].season_name,
                                days: price_breakdown[index].days,
                                original_price: price_breakdown[index].price,
                                custom_price: parseFloat(input.val()) || 0
                            });
                        });

                      // Compute Total Days
                        const total_days = custom_breakdown.reduce((acc, item) => {
                            return acc + item.days;
                        }, 0);

                      // Update Total Rate
                        // setRoomPriceContext(currentContext, new_total_rate);
                        const subtotal = (new_total_rate / total_days).toFixed(2);
                        $('#precio_final').val(subtotal).trigger('input');
                    }

                    showToast (
                        translateAndReplace("entity_forms.reservation.adjusted_rate"),
                        "#3E87A1", "#0D6889"
                    );
                });
            }
        }
    }

    function updateRoomLimitManually() {
      // Control Input
        const $selected_option = $('#select-type option:selected');

      // Extract Data
        const limit = $selected_option.data('limit');
        const minimum_stay = $selected_option.data('minimum-stay');

      // Update Constants
        window.minimum_stay = minimum_stay ? parseInt(minimum_stay) : null;
        window.room_limit = limit ? parseInt(limit) : null;
    }

    function respectRoomLimit() {
      // Control Data
        const number_adults = $('#reserva_adultos').val();
        const number_children = $('#reserva_ninos').val();

      // Calculate PAX quantity
        let total_pax = parseInt(number_adults) + parseInt(number_children);

        // If room type haven't been selected, conclude process
        if (window.room_limit === null) return;

        // If room limit have been reached
        if (window.room_limit < total_pax) {
            showToast (
                translateAndReplace('entity_forms.reservation.room_limit_reached', { limit: window.room_limit }),
                "#C34808",
                "#78350F"
            );
        }

        return;
    }

/* Automatic Date Price */
    function isValidTime(value) {
        const timeRegex = /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/; // Matches HH:mm format
        return timeRegex.test(value);
    }

    function divideDatetime(inputId, isEntryDate) {
        const datetimeValue = $(`#${inputId}`).val();
            if (!datetimeValue) return;

        const [fecha, hora] = datetimeValue.split('T');

        if(!isValidTime(hora)) {
            showToast (
                translateAndReplace("entity_forms.reservation.invalid_dates"),
                "#E02424", "#C81E1E"
            );
            return
        }

        const prefix = isEntryDate ? 'ini' : 'fin';
        $(`#date${prefix}`).val(fecha).trigger("change");
        $(`#time${prefix}`).val(hora);
    }

    $(function () {
      // Triggers
        $('#dateini, #datefin').on('change', checkDatesHandler);
    });

    async function checkDatesHandler(e) {
      //  Define Trigger Input
        const is_checkin_input = e.target.id === 'dateini';

        // Disable submit action
        $('#action_button')
            .val(`${translateAndReplace("common_actions.wait")}....`)
            .prop("disabled", true);

        setTimeout(async () => {
            // Enable submit action
            $('#action_button')
                .val(translateAndReplace("common_actions.update"))
                .prop("disabled", false);;

            calcularEstancia();

            // Check if Price and Availability has changed
            if ($('#select-type').val() != null)
                await onSelectTypeChange.call($('#select-type')[0]); //Volvemos a revisar si hay habitaciones disponibles

            if ($('#select-room').val() != null && $('#select-type').val() != 2)
                onSelectRoomChange.call($('#select-room')[0]); //Volvemos a revisar el precio por temporada

        }, 500);
    }


/* Payments & Charges */
  /* Form Triggers */
    $(document).ready(function () {
      // Pagos
        $('#lodging_payment_form').on('submit', (e) => handleBalanceFormSubmit(e, 'lodging_pay'));
        $('#consumption_payment_form').on('submit', (e) => handleBalanceFormSubmit(e, 'consumption_pay'));
        $('#extra_payment_form').on('submit', (e) => handleBalanceFormSubmit(e, 'extra_pay'));

      // Cargos
        $('#consumption_charge_form').on('submit', (e) => handleBalanceFormSubmit(e, 'consumption_charge'));
        $('#extra_charge_form').on('submit', (e) => handleBalanceFormSubmit(e, 'extra_charge'));
    });

  /* Funciones de Creación/Actualización */
    function handleBalanceFormSubmit(event, type) {
      //* Environment
        event.preventDefault();
        const form = event.target;

      //* Set Type Configuration (Lodging/Consumption/Extra) - (Payments/Charges)
        const config_map = {
            'lodging_pay': {
                create_url: config.routes.lodgingPayment,
                update_url: config.routes.updateLodgingPayment,
                btn: '#add_lodgingP', reservation_id_input: '#lodging_payment_reservation',
                callback: loadLodgingPayments,
                labels: ["entity_forms.reservation.register_payment", "entity_forms.reservation.update_payment"]
            },
            'consumption_pay': {
                create_url: config.routes.consumptionPayment,
                update_url: config.routes.updateConsumptionPayment,
                btn: '#add_consumptionP', reservation_id_input: '#consumption_payment_reservation',
                callback: loadConsumptionData,
                labels: ["entity_forms.reservation.register_payment", "entity_forms.reservation.update_payment"]
            },
            'extra_pay': {
                create_url: config.routes.extraPayment,
                update_url: config.routes.updateExtraPayment,
                btn: '#add_extraP', reservation_id_input: '#extra_payment_reservation',
                callback: loadExtraData,
                labels: ["entity_forms.reservation.register_payment", "entity_forms.reservation.update_payment"]
            },
            'consumption_charge': {
                create_url: config.routes.consumptionCharge,
                update_url: config.routes.updateConsumptionCharge,
                btn: '#add_consumptionC', reservation_id_input: '#consumption_charge_reservation',
                callback: loadConsumptionData,
                labels: ["common_actions.register", "common_actions.update"]
            },
            'extra_charge': {
                create_url: config.routes.extraCharge,
                update_url: config.routes.updateExtraCharge,
                btn: '#add_extraC', reservation_id_input: '#extra_charge_reservation',
                callback: loadExtraData,
                labels: ["common_actions.register", "common_actions.update"]
            }
        }[type];
            if (!config) return;

      //* Control Data
        const is_update = $(config_map.btn).val() === translateAndReplace(config_map.labels[1]);
        const target_url = is_update ? config_map.update_url : config_map.create_url;
        const reservation_id = $(config_map.reservation_id_input).val();

      //* Request Data to Create/Update
        $.ajax({
            url: target_url,
            method: "POST",
            data: new FormData(form),
            contentType: false,
            cache: false,
            processData: false,
            dataType: "json",
            success: function (data) {
              // Control Variables
                const is_home_page = window.location.pathname === '/home';
                const is_calendar_page = window.location.pathname === '/calendar';

              // Success Message
                if (!is_calendar_page)
                    Swal.fire(
                        translateAndReplace("common_responses_and_messages.success"),
                        translateAndReplace(is_update ? "common_responses_and_messages.updated_successfully" : "common_responses_and_messages.created_successfully"),
                        'success'
                    );

              // Reset Form & Spread Data
                form.reset();
                config_map.callback(reservation_id);

                // Reset Button Action
                if (is_update)
                    $(config_map.btn).val(translateAndReplace(config_map.labels[0]));

              // Update Background Data
                if (is_home_page) reservesOnTimeDebounced();

                if (is_calendar_page) {
                    if (window.is_normal_calendar) updateCalendarEventsDebounced();
                    if (window.is_express_calendar) updateCalendarExpressEventsDebounced();
                }
            }
        });
    }

  /* Funciones de Edición */
    function editReservationBalance(id, type) {
      //* Set Type Configuration (Lodging/Consumption/Extra) - (Payments/Charges)
        const config = {
            'lodging_pay': {
                url: `reservation-payments/lodging/${id}/edit`,
                prefix: 'lodging_payment', btn: '#add_lodgingP',
                msg: "entity_forms.reservation.update_payment",
                is_payment: true
            },
            'extra_pay': {
                url: `reservation-payments/extra/${id}/edit`,
                prefix: 'extra_payment', btn: '#add_extraP',
                msg: "entity_forms.reservation.update_payment",
                is_payment: true
            },
            'consumption_pay': {
                url: `reservation-payments/consumption/${id}/edit`,
                prefix: 'consumption_payment', btn: '#add_consumptionP',
                msg: "entity_forms.reservation.update_payment",
                is_payment: true
            },
            'extra_charge': {
                url: `reservation-charges/extra/${id}/edit`,
                prefix: 'extra_charge', btn: '#add_extraC',
                msg: "common_actions.update",
                is_payment: false
            },
            'consumption_charge': {
                url: `reservation-charges/consumption/${id}/edit`,
                prefix: 'consumption_charge', btn: '#add_consumptionC',
                msg: "common_actions.update",
                is_payment: false
            }
        }[type];
            if (!config) return;

      //* Update Visual Controls
        $(config.btn).val(translateAndReplace(config.msg));

      //* Request Data to Edit
        $.ajax({
            url: `/${config.url}`,
            dataType: "json",
            success: function (response) {
              // Control Data
                const data = response.data;
                const prefix = config.prefix;

              // Seed Common Fields
                $(`#${prefix}_id`).val(data.id);
                $(`#${prefix}_reservation`).val(data.reservation_id);

              // Seed Specific Fields
                if (config.is_payment) { // Payments
                    const parsed_date = moment(data.payment_date).format('YYYY-MM-DDTHH:mm');

                    $(`#${prefix}_date`).val(parsed_date);
                    $(`#${prefix}_concept`).val(data.payment_concept);
                    $(`#${prefix}_method`).val(data.payment_method);
                    $(`#${prefix}_amount`).val(data.payment_price);
                } else { // Charges
                    const field = type.split('_')[0]; // 'extra' o 'consumption'
                    const parsed_date = moment(data[`${field}s_date`] || data[`${field}_date`]).format('YYYY-MM-DDTHH:mm');

                    $(`#${prefix}_date`).val(parsed_date);
                    $(`#${prefix}_concept`).val(data[`${field}s_concept`] || data[`${field}_concept`]);
                    $(`#${prefix}_amount`).val(data[`${field}s_price`] || data[`${field}_price`]);
                }
            }
        });
    }

  /* Funciones de Eliminación */
    function deleteReservationBalance(id, type) {
      //* Set Type Configuration (Lodging/Consumption/Extra) - (Payments/Charges)
        const config = {
            'lodging_pay':        { url: 'reservation-payments/lodging',     callback: loadLodgingPayments },
            'consumption_pay':    { url: 'reservation-payments/consumption', callback: loadConsumptionData },
            'extra_pay':          { url: 'reservation-payments/extra',       callback: loadExtraData },
            'consumption_charge': { url: 'reservation-charges/consumption',  callback: loadConsumptionData },
            'extra_charge':       { url: 'reservation-charges/extra',        callback: loadExtraData }
        }[type];
            if (!config) return;

      //* Throw Advice
        Swal.fire({
            title: translateAndReplace("common_responses_and_messages.confirm_deletion_short"),
            showCancelButton: true,
            confirmButtonText: translateAndReplace("common_actions.delete"),
            icon: "warning",
        }).then((result) => {
            if (result.isConfirmed) {
                $.ajax({
                    url: `/${config.url}/${id}/destroy`,
                    success: function (data) {
                      //* Control Variables
                        const is_home_page = window.location.pathname === '/home';
                        const is_calendar_page = window.location.pathname === '/calendar';

                      //* Messages
                        if (!is_calendar_page)
                            Swal.fire({
                                toast: true,
                                position: 'top-end',
                                showConfirmButton: false,
                                timer: 2500,
                                timerProgressBar: true,
                                title: translateAndReplace("common_responses_and_messages.updating_data"),
                                icon: 'success',
                            });

                        // Redraw & Recompute Balances
                        config.callback(data);
                        // setTimeout(() => config.callback(data), 1500);

                      //* Update Background Data
                        if (is_home_page) reservesOnTimeDebounced();

                        if (is_calendar_page) {
                            if (window.is_normal_calendar) updateCalendarEventsDebounced();
                            if (window.is_express_calendar) updateCalendarExpressEventsDebounced();
                        }
                    }
                });
            }
        });
    }

  /* Funciones de Carga */
    function loadReservationPaymentsAndCharges(id) {
      //* Clean Sections
        $(`
            #lodgingResume,
            #ConsumptionChargesResume, #ConsumptionPaymentsResume,
            #ExtraChargesResume, #ExtraPaymentsResume
        `).empty();

      // Load Data
        $.get(`/api/reservations/${id}/payments-and-charges`, function (data) {
            processPaymentsAndChargesData('lodging_pay', data.lodging_payments, false);
            processPaymentsAndChargesData('consumption_pay', data.consumption_payments);
            processPaymentsAndChargesData('consumption_charge', data.consumption_charges, false);
            processPaymentsAndChargesData('extra_pay', data.extra_payments);
            processPaymentsAndChargesData('extra_charge', data.extra_charges, false);
        });
    }

    function loadLodgingPayments(id){
        $("#lodgingResume").empty();
        $.get(`/api/reservation-payments/${id}/lodging`, data => processPaymentsAndChargesData('lodging_pay', data));
    }

    function loadConsumptionData(id){
        $("#ConsumptionChargesResume, #ConsumptionPaymentsResume").empty();

        Promise.all([
            $.get(`/api/reservation-payments/${id}/consumption`),   // Payments
            $.get(`/api/reservation-charges/${id}/consumption`)     // Charges
        ])
        .then(([payments, charges]) => {
            processPaymentsAndChargesData('consumption_pay', payments);
            processPaymentsAndChargesData('consumption_charge', charges);
        });
    }

    function loadExtraData(id) {
        $("#ExtraChargesResume, #ExtraPaymentsResume").empty();

        Promise.all([
            $.get(`/api/reservation-payments/${id}/extra`), // Payments
            $.get(`/api/reservation-charges/${id}/extra`)   // Charges
        ])
        .then(([payments, charges]) => {
            processPaymentsAndChargesData('extra_pay', payments);
            processPaymentsAndChargesData('extra_charge', charges);
        });
    }

  /* Support Functions */
    // Alerts
        function notifyFavorableBalance(amount, category) {
          // Control Data
            amount = formatCurrency(amount.toFixed(2));

          // Display Modal
            Swal.fire({
                icon: 'warning',
                title: translateAndReplace('entity_forms.reservation.favorable_balance_title'),
                html: `
                    ${translateAndReplace('entity_forms.reservation.favorable_balance_description', { category })}
                    ${translateAndReplace('entity_forms.reservation.favorable_balance_amount', { amount })}
                `,
                confirmButtonText: translateAndReplace("common_responses_and_messages.ok"),
            });
        }

    // Payments & Charges
        function processPaymentsAndChargesData(type, data, notify_favorable_balance = true) {
          //* Control Data
            let html = ""; // HTML to render
            let saldo_pagado = 0.00;
            let saldo_total = 0.00;
            let saldo_pendiente = 0.00;

            // Set Type Configuration (Lodging/Consumption/Extra) - (Payments/Charges)

            const config = {
                'lodging_pay': {
                    entity_field: 'payment_price', table_summary: '#lodgingResume', updates: ['#lodging_payment'],
                    remaining_balance: '#lodging_left', updateFunc: 'editReservationBalance', deleteFunc: 'deleteReservationBalance',
                    is_payment: true, cols: 5, trans: 'entity_forms.reservation.sections.lodging'
                },
                'consumption_pay': {
                    entity_field: 'payment_price', table_summary: '#ConsumptionPaymentsResume', updates: ['#consumption_payment', '#consumption_payment_2'],
                    remaining_balance: null, updateFunc: 'editReservationBalance', deleteFunc: 'deleteReservationBalance',
                    is_payment: true, cols: 5, trans: ''
                },
                'extra_pay': {
                    entity_field: 'payment_price', table_summary: '#ExtraPaymentsResume', updates: ['#extra_payment', '#extra_payment_2'],
                    remaining_balance: null, updateFunc: 'editReservationBalance', deleteFunc: 'deleteReservationBalance',
                    is_payment: true, cols: 5, trans: ''
                },
                'consumption_charge': {
                    entity_field: 'consumption_price', table_summary: '#ConsumptionChargesResume', updates: ['#consumption_final', '#consumption_final_2'],
                    remaining_balance: ['#consumption_left', '#consumption_left_2'], updateFunc: 'editReservationBalance', deleteFunc: 'deleteReservationBalance',
                    is_payment: false, cols: 4, trans: 'entity_forms.reservation.sections.consumption'
                },
                'extra_charge': {
                    entity_field: 'extras_price', table_summary: '#ExtraChargesResume', updates: ['#extra_final', '#extra_final_2'],
                    remaining_balance: ['#extra_left', '#extra_left_2'], updateFunc: 'editReservationBalance', deleteFunc: 'deleteReservationBalance',
                    is_payment: false, cols: 4, trans: 'entity_forms.reservation.sections.extra_charges'
                }
            }[type];
                if (!config) return;

          //* Process Date
            if (data.length) {
                data.forEach(item => {
                  // Render Data
                    const inactive = item.status != 'Activo';
                    const price = inactive ? 0 : parseFloat(item[config.entity_field]);

                  // Amount Compute
                    if (config.is_payment) saldo_pagado += price;
                    else saldo_total += price;

                  // Increment HTML to Render
                    html += createRow(item, {
                        is_payment_row: config.is_payment,
                        updateFunction: config.updateFunc,
                        deleteFunction: config.deleteFunc,
                        type: type,
                        inactive
                    });
                });
            } else {
                html = createEmptyTableRow(config.cols);
            }

            // Compute Remaining Balance
            if (type === 'lodging_pay') { // Lodging
                let lodging_charges = parseFloat($('#tarifaTotal').val());
                saldo_pendiente = lodging_charges - saldo_pagado;
            } else if (!config.is_payment) { // Consumption & Extras
                let amount_paid = parseFloat($(config.updates[0].replace('final', 'payment')).val()) || 0;
                saldo_pendiente = saldo_total - amount_paid;
            }

          //* Render Structures
            // Tables
            $(config.table_summary).html(html);

            // Total Fields
            const value_to_render = config.is_payment ? saldo_pagado : saldo_total;
            config.updates.forEach(id => $(id).val(value_to_render.toFixed(2)));

            // Remaining Balance & Notifies
            if (config.remaining_balance) {
                const target_left = Array.isArray(config.remaining_balance) ? config.remaining_balance : [config.remaining_balance];
                target_left.forEach(id => $(id).val(saldo_pendiente.toFixed(2)));

                if (saldo_pendiente < 0 && notify_favorable_balance) {
                    notifyFavorableBalance(Math.abs(saldo_pendiente), translateAndReplace(config.trans));
                }
            }
        }

    // Build Summary Rows
        function createEmptyTableRow(colspan) {
            return `
                <tr class="inactive-row">
                    <td class="bg-light" colspan="${colspan}">${translateAndReplace('data_tables.sEmptyTable')}</td>
                </tr>`;
        }
        function createRow(item, {is_payment_row = true, updateFunction = null, deleteFunction = null, type = '', inactive = false} = {}) {
          //* Define Row Data
            // Item Data
            let date = is_payment_row
                ? item.payment_date : (item.consumption_date || item.extras_date);

            date = moment(date).format('YYYY-MM-DD, HH:mm');

            const concept = is_payment_row
                ? item.payment_concept : (item.consumption_concept || item.extras_concept);

            const method = is_payment_row ? item.payment_method : null;

            const price = is_payment_row
                ? item.payment_price : (item.consumption_price || item.extras_price);

            // Render Data
            const cell_class = inactive ? 'statusDelete' : 'bg-light';

          //* Define Data
            return `
                <tr class="${inactive ? 'inactive-row' : ''}">
                    <td class="${cell_class}">${date}</td>
                    <td class="${cell_class}">${concept}</td>
                    ${is_payment_row ? `<td class="${cell_class}">${method}</td>` : ''}
                    <td class="${cell_class}">${price}</td>
                    <td class="${cell_class}">
                        ${
                            inactive ? ''
                            : `
                                <button type="button" onclick="${updateFunction}(${item.id}, '${type}')" class="btn btn-primary btn-sm">
                                    <i class="fas fa-edit"></i>
                                </button>
                                <button type="button" onclick="${deleteFunction}(${item.id}, '${type}')" class="btn btn-danger btn-sm">
                                    <i class="fas fa-trash-alt"></i>
                                </button>
                            `
                        }
                    </td>
                </tr>
            `;
        }

/* Update Contracts */
    $(function () {
        $('#consumptionContract').on('input', changeConsumptionContract);
        $('#consumptionContract_2').on('input', changeConsumptionContract);
        $('#extraContract').on('input', changeExtraContract);
        $('#extraContract_2').on('input', changeExtraContract);
    });

    function changeConsumptionContract() {
        // console.log("Consumo");
        var reservation_id = $('#hidden_id').val();
        var contractType = $(this).val();
        $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            url: `/api/reservations/${reservation_id}/consumption-contract`,
            type: 'PATCH',
            data: {
                type: contractType,
                receptionist: config.data.receptionist,
            },
            success: function (data) {
                Swal.fire({
                    toast: true,
                    position: 'top-end',
                    showConfirmButton: false,
                    timer: 2500,
                    timerProgressBar: true,
                    title: `${translateAndReplace("common_responses_and_messages.update")} <b class="success-message">${translateAndReplace("common_responses_and_messages.completed")}</b>`,
                    icon: 'success',
                });

                $('#consumptionContract').val(contractType);
                $('#consumptionContract_2').val(contractType);

            }
        });
    }

    function changeExtraContract() {
        // console.log("Extra");
        var reservation_id = $('#hidden_id').val();
        var contractType = $(this).val();
        $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            url: `/api/reservations/${reservation_id}/extras-contract`,
            type: 'PATCH',
            data: {
                type: contractType,
                receptionist: config.data.receptionist,
            },
            success: function (data) {
                Swal.fire({
                    toast: true,
                    position: 'top-end',
                    showConfirmButton: false,
                    timer: 2500,
                    timerProgressBar: true,
                    title: `${translateAndReplace("common_responses_and_messages.update")} <b class="success-message">${translateAndReplace("common_responses_and_messages.completed")}</b>`,
                    icon: 'success',
                });

                $('#extraContract').val(contractType);
                $('#extraContract_2').val(contractType);

            }
        });
    }

/* Formatters y Calculadores */
    function calcularEstancia() {
      // Extract Data
        const is_express = Boolean(Number($('#is_express_reserve').val()));
        const has_control_hours = window.config.data.features.has_control_hours;

        const date_ini = $('#dateini').val();
        const time_ini = $('#timeini').val() || "13:00";

        const date_fin = $('#datefin').val();
        const time_fin = $('#timefin').val() || "12:00";

        // Create Date time from individual fields
        const start = moment(`${date_ini} ${time_ini}`, "YYYY-MM-DD HH:mm");
        const end   = moment(`${date_fin} ${time_fin}`, "YYYY-MM-DD HH:mm");

      // Validate Data
        // Ensure values are valid Dates
        if (!start.isValid() || !end.isValid()) {
            $("#reserva_noches, #reserva_horas").val(0);

            showToast(
                translateAndReplace("entity_forms.reservation.invalid_dates"),
                "#E02424", "#C81E1E"
            );
            return;
        }

        // Avoid Negative Stays
        if (end.isBefore(start) && !is_express) {
            showToast(
                translateAndReplace("entity_forms.reservation.negative_stay"),
                "#825CF5", "#9470FF"
            );
            return;
        }

      // Calculate stay
        // Control Data
        let nights = 0;
        let hours = 0;

        const CHECKOUT_HOUR = 12; // 12 => Considerar tiempo de Limpieza, 13 => 24h exactas

        // Compute stay based on model
        if (has_control_hours) { // System use dynamic stays

            if (is_express) { // Express (Only Hours)
                const totalMinutes = end.diff(start, 'minutes');
                hours = Math.ceil(totalMinutes / 60);
                nights = 0;

            } else { // Dynamic (Nights + Hours)
                nights = end.clone().startOf('day')
                    .diff(start.clone().startOf('day'), 'days'); // Noches de estancia (mínimo 1)

                nights = Math.max(1, nights); // Siempre al menos 1 noche, si hay estancia válida

                let base_checkout = start.clone().add(nights, 'days') // Checkout teórico (última noche)
                    .hour(CHECKOUT_HOUR).minute(0).second(0);

                // Horas extra (solo después del checkout)
                if (end.isAfter(base_checkout))
                    hours = Math.ceil(end.diff(base_checkout, 'minutes') / 60);
                else
                    hours = 0;
            }

        } else { // Traditional Stays (Only Nights)
            nights = end.clone().startOf('day')
                .diff(start.clone().startOf('day'), 'days'); // Noches de estancia

            let base_checkout = start.clone().add(nights, 'days') // Checkout teórico
                .hour(CHECKOUT_HOUR).minute(0).second(0);

            if (end.isBefore(base_checkout)) { // Si el cliente se va ANTES del checkout, no cuenta como noche completa
                nights -= 1;

                base_checkout = start.clone().add(nights, 'days')
                    .hour(CHECKOUT_HOUR).minute(0).second(0);
            }

            if (end.isAfter(base_checkout)) // Horas extra después del checkout
                hours = Math.ceil(end.diff(base_checkout, 'minutes') / 60);

            // Avoid negative values
            nights = Math.max(0, nights);
            hours = Math.max(0, hours);
        }

      // Apply results
        $("#reserva_noches").val(nights);
        $("#reserva_horas").val(hours);

        calcularTotal();
    }

    function calcularTotal() {
      // Control Data
        const is_express = Boolean(Number($('#is_express_reserve').val()));

      // Extracted Data
        const selected_tariff = parseFloat($("#precio_final").val()) || 0;
        const period_quantity = parseInt($("#reserva_noches").val(), 10) || 0;

        const reservation_total = is_express
            ? parseFloat(selected_tariff)
            : Math.round(period_quantity * selected_tariff);

        $("#total").val(reservation_total.toFixed(2));
    }

    function calculateDiscount() {
        if (getFeatureStatus("discounts")){
            const precio_original = parseFloat( $("#precio_original_sugerido").val().replace(/,/g, '') );
            let discount_percentage = parseFloat( $("#discount").val() );

            if( Number.isNaN(discount_percentage)  )
                discount_percentage = 0.0;

            const discount = (precio_original * discount_percentage) / 100;
            const discounted_amount = (precio_original - discount).toFixed(2);

            $("#precio_sugerido").val(discounted_amount);
        }

        return;
    }

    function redondearDecimales(inputId) {

        var result = 0;
        var numero = $('#' + inputId).val();
        numero = parseFloat(numero);

        numeroRegexp = new RegExp('\\d\\.(\\d){' + 2 + ',}'); // Expresion regular para numeros con un cierto numero de decimales o mas
        if (numeroRegexp.test(numero)) { // Ya que el numero tiene el numero de decimales requeridos o mas, se realiza el redondeo
            result = Number(numero.toFixed(2));
            $("#" + inputId).val(result);
        } else {
            result = Number(numero.toFixed(2)) === 0 ? 0 : numero; // En valores muy bajos, se comprueba si el numero es 0 (con el redondeo deseado), si no lo es se devuelve el numero otra vez.
            $("#" + inputId).val(result);
        }
    }

    function ensureIntegerLimit(input, default_integer = 0) {
        let min = parseInt(input.min);
        let max = parseInt(input.max);
        let value = input.value;

        value = parseInt(value ?? default_integer);

        if (value < min) value = min;
        if (value > max) value = max;

        input.value = value;
    }

/* Support Functions */
    function showToast(text, gradient_from, gradient_to, gravity="bottom", position="center", additional_data = {}) {
        Toastify({
            text,
            duration: toast_duration,
            close: false,
            gravity, // `top` or `bottom`
            position, // `left`, `center` or `right`
            avatar: config.assets.toastInfoIcon,
            style: {
                background: `linear-gradient(to right, ${gradient_from}, ${gradient_to})`,
            },
            ...additional_data,
            //   onClick: function(){}
            //   destination: "https://github.com/apvarun/toastify-js",
            //   newWindow: true,
        }).showToast();
    }

/* Guardar Cambios */
    $(document).ready(function () {
        $(document).off('submit', '#sample_form');

        $(document).on('submit', '#sample_form', async function (event) {
            event.preventDefault();

          // Validate Payment Status
            const status_selected = $('#guest_estatus_id').val();
            const reservationId = $('#hidden_id').val();

                if (status_selected === '6'){
                    await checkPaymentAndCharges(reservationId);
                } else {
                    window.let_reserve_checkout = true;
                }

          // Prepare Data
            const reservation_form_data = new FormData(this);

            // Complementary Data
            reservation_form_data.append('reference_invoice_uuid', $('#reference_invoice_uuid').val());

          // Submit Data
            if(window.let_reserve_checkout) {
                $.ajax({
                    url: config.routes.reservationUpdate,
                    method: "POST",
                    data: reservation_form_data,
                    contentType: false,
                    cache: false,
                    processData: false,
                    dataType: "json",

                    success: function () {
                      //* Control Variables
                        const is_home_page = window.location.pathname === '/home';
                        const is_calendar_page = window.location.pathname === '/calendar';

                      //* Messages
                        if (!is_calendar_page)
                            Swal.fire(
                                translateAndReplace("common_responses_and_messages.success"),
                                translateAndReplace("common_responses_and_messages.updated_successfully"),
                                'success'
                            );

                      //* Reset interface
                        $('#formModal').modal('hide');
                        $('#sample_form')[0].reset();
                        $('#action_button').val(translateAndReplace("common_actions.update"));

                        window.let_reserve_checkout = false;

                      //* Update Background Data
                        if (is_home_page) reservesOnTimeDebounced();

                        if (is_calendar_page) {
                            if (window.is_normal_calendar) updateCalendarEventsDebounced();
                            if (window.is_express_calendar) updateCalendarExpressEventsDebounced();
                        }
                    },

                    error: function(data){
                        const response = data.responseJSON;

                        // Validator Errors
                        const errors = response.errors;
                        Object.keys(errors).forEach(key => {
                            errors[key].forEach(message => showToast(message, "#C34808", "#78350F", "bottom", "right"));
                        });

                        return;
                    },
                });
            }

        });

        // On close Edit Reservation Modal form
        $('#formModal').on('hide.bs.modal', function () {
            document.activeElement.blur();
        });

        // Check PaymentAndCharges
        function checkPaymentAndCharges(id) {
            return new Promise((resolve) => {
                $.get(`/api/reservations/${id}/check-payments-and-charges`, async function (data) {
                    data = JSON.parse(data);

                    const {
                        // Saldos Faltantes
                        extraPayment_left,
                        consumptionPayment_left,
                        lodgingPayment_left,

                        // Contratos de Reservación
                        extras_contract,
                        consumption_contract,
                        lodging_contract
                    } = data;

                    // Variables Liberadoras
                    const extras_closed = await approveSection(extraPayment_left, extras_contract);
                    const consumption_closed = await approveSection(consumptionPayment_left, consumption_contract);
                    const lodging_closed = await approveSection(lodgingPayment_left, lodging_contract);

                    const isReleased = extras_closed && consumption_closed && lodging_closed;
                    window.let_reserve_checkout = isReleased;

                    // Validar Saldos
                    if (!isReleased) {
                        window.let_reserve_checkout= false;
                        Swal.fire({
                            icon: 'error',
                            title: translateAndReplace("common_responses_and_messages.rejected_action"),
                            confirmButtonText: translateAndReplace("common_responses_and_messages.ok"),
                            html: `
                                <div class="container mb-0 pb-0 text-start">
                                    <p>${translateAndReplace("entity_forms.reservation.rejected_checkout")}</p>
                                    <ul class="text-start ms-5" style="list-style-type: none; padding: 0;">
                                        ${lodging_closed ? '' : `<li class="fw-semi-bold"> ${translateAndReplace("entity_forms.reservation.sections.lodging")} </li>`}
                                        ${consumption_closed ? '' : `<li class="fw-semi-bold"> ${translateAndReplace("entity_forms.reservation.sections.consumption")} </li>`}
                                        ${extras_closed ? '' : `<li class="fw-semi-bold"> ${translateAndReplace("entity_forms.reservation.sections.extra_charges")} </li>`}
                                    </ul>
                                    <p style="font-size: 95%; color: #777;">
                                        ${translateAndReplace("entity_forms.reservation.check_balances")}
                                    </p>
                                </div>
                                `,
                        });
                    }

                    resolve();
                });
            });
        }

        function approveSection(saldoPendiente, contrato) {
            if (contrato === "Cortesia" || contrato === "Credito")
                return true;

            if (contrato === "Pago en Destino")
                return saldoPendiente <= 0;

            return false;
        }
    });
