/**
 * WooCommerce Equipment Rental - Product Page Script
 *
 * Depends on: flatpickr (bundled), wcRentData (wp_localize_script)
 * No jQuery dependency.
 */
(function () {
    'use strict';

    // Guard: only run when the necessary globals exist
    if (typeof flatpickr === 'undefined' || typeof wcRentData === 'undefined') {
        return;
    }

    var data = wcRentData;

    // -------------------------------------------------------------------------
    // Utility: format a number as currency per wcRentData settings
    // -------------------------------------------------------------------------
    function formatCurrency(amount) {
        var num = parseFloat(amount);
        if (isNaN(num)) { num = 0; }
        var fixed = num.toFixed(data.decimals);
        var parts = fixed.split('.');
        var intPart = parts[0];
        var decPart = parts.length > 1 ? parts[1] : '';

        // Thousands separator
        if (data.thousand_sep) {
            intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, data.thousand_sep);
        }

        var formatted = decPart.length ? intPart + data.decimal_sep + decPart : intPart;
        var sym = data.currency_symbol;

        switch (data.currency_pos) {
            case 'left':        return sym + formatted;
            case 'right':       return formatted + sym;
            case 'left_space':  return sym + ' ' + formatted;
            case 'right_space': return formatted + ' ' + sym;
            default:            return sym + formatted;
        }
    }

    // -------------------------------------------------------------------------
    // Utility: format a JS Date for display (e.g. "Jan 15")
    // -------------------------------------------------------------------------
    function formatDisplayDate(dateObj) {
        var opts = { month: 'short', day: 'numeric' };
        return dateObj.toLocaleDateString( document.documentElement.lang || 'en', opts );
    }

    // -------------------------------------------------------------------------
    // Build the Flatpickr `disable` array from booked ranges
    // Each booked range disables all dates from `from` through `to` inclusive.
    // -------------------------------------------------------------------------
    function buildDisabledRanges() {
        if ( ! data.availability_check_enabled ) {
            return [];
        }
        return data.booked_dates.map( function( range ) {
            if ( ! range.from || ! range.to ) {
                return null;
            }
            return { from: range.from, to: range.to };
        }).filter( Boolean );
    }

    // -------------------------------------------------------------------------
    // Calculate total rental price with tiered weekly pricing.
    // Mirrors WCRent_Rental_Price::get_base_rental_price() in PHP:
    // price_per_day is -1 when no daily rate is configured (weekly-only),
    // in which case remaining days are prorated at one-seventh of the weekly rate.
    // -------------------------------------------------------------------------
    function calcTotal( days ) {
        var priceWeek = parseFloat( data.price_per_week ) || 0;
        var priceDay  = parseFloat( data.price_per_day );
        if ( isNaN( priceDay ) ) { priceDay = -1; }

        var fullWeeks     = Math.floor( days / 7 );
        var remainingDays = days % 7;

        if ( priceDay >= 0 ) {
            if ( priceWeek > 0 && days >= 7 ) {
                return ( fullWeeks * priceWeek ) + ( remainingDays * priceDay );
            }
            return days * priceDay;
        }

        if ( priceWeek > 0 ) {
            return Math.round( ( ( fullWeeks * priceWeek ) + ( remainingDays * ( priceWeek / 7 ) ) ) * 100 ) / 100;
        }

        // Mirrors the final fallback in WCRent_Rental_Price::get_base_rental_price().
        // Reached by e.g. an hourly-only product with a multi-day selection, where
        // returning 0 would preview $0.00 while the cart charges the base price.
        return parseFloat( data.price_base ) || 0;
    }

    // -------------------------------------------------------------------------
    // Remote availability check via REST API
    // -------------------------------------------------------------------------
    var currentAvailabilityController = null;

    function checkAvailabilityRemote( startDate, endDate, qty ) {
        if ( ! data.availability_check_enabled ) {
            return;
        }

        // Cancel any in-flight request to avoid stale responses clearing a
        // valid selection made while the previous fetch was still pending.
        if ( currentAvailabilityController ) {
            currentAvailabilityController.abort();
        }
        currentAvailabilityController = new AbortController();
        var signal = currentAvailabilityController.signal;

        var params = new URLSearchParams( {
            product_id: data.product_id,
            start: startDate,
            end: endDate,
            qty: qty,
            nonce: data.nonce || '',
        } );
        var url = data.rest_url + '?' + params.toString();

        if ( addToCartBtn ) { addToCartBtn.disabled = true; }

        fetch( url, { signal: signal } )
        .then( function( response ) {
            if ( ! response.ok ) { throw new Error( response.statusText ); }
            return response.json();
        } )
        .then( function( result ) {
            currentAvailabilityController = null;
            if ( addToCartBtn ) { addToCartBtn.disabled = false; }
            if ( result.is_available === false ) {
                showError( data.i18n.unavailable );
                // clear(false) suppresses the recursive onChange, whose first
                // action (clearError) would wipe the message just shown.
                if ( fpInstance ) { fpInstance.clear( false ); }
                resetSelection();
            }
        } )
        .catch( function( err ) {
            if ( err.name === 'AbortError' ) {
                // A new request is already in-flight — leave the button disabled.
                return;
            }
            currentAvailabilityController = null;
            if ( addToCartBtn ) { addToCartBtn.disabled = false; }
            // Show a non-blocking warning so the customer knows availability is unconfirmed.
            showError( data.i18n.availability_error || 'Could not confirm availability — please proceed or try again.' );
        } );
    }

    // -------------------------------------------------------------------------
    // DOM references (populated after DOMContentLoaded)
    // -------------------------------------------------------------------------
    var inputEl;
    var summaryEl;
    var errorEl;
    var startHidden;
    var endHidden;
    var daysHidden;
    var qtyInput;
    var addToCartBtn;
    var form;
    var startTimeInput;
    var endTimeInput;
    var timePicker;

    // Flatpickr instance
    var fpInstance = null;

    // Selected dates cache
    var selectedStart = null;
    var selectedEnd = null;

    // -------------------------------------------------------------------------
    // Show / clear error
    // -------------------------------------------------------------------------
    function showError( msg ) {
        if ( ! errorEl ) { return; }
        errorEl.textContent = msg;
    }

    function clearError() {
        if ( ! errorEl ) { return; }
        errorEl.textContent = '';
    }

    // -------------------------------------------------------------------------
    // Reset hidden fields and summary
    // -------------------------------------------------------------------------
    function resetSelection() {
        selectedStart = null;
        selectedEnd = null;

        if (startHidden) startHidden.value = '';
        if (endHidden)   endHidden.value   = '';
        if (daysHidden)  daysHidden.value  = '';

        if (summaryEl) summaryEl.classList.add( 'wcrent-visually-hidden' );
        hideTimePicker();
    }

    // -------------------------------------------------------------------------
    // Pad a date part to 2 digits
    // -------------------------------------------------------------------------
    function pad2(n) {
        return n < 10 ? '0' + n : String(n);
    }

    // -------------------------------------------------------------------------
    // Format a Date as YYYY-MM-DD (local, not UTC)
    // -------------------------------------------------------------------------
    function toYMD(d) {
        return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate());
    }

    // -------------------------------------------------------------------------
    // Returns true when this is a same-day rental on a product with hourly rate
    // -------------------------------------------------------------------------
    function isHourlyMode(start, end) {
        return (data.price_per_hour || 0) > 0 && toYMD(start) === toYMD(end);
    }

    // -------------------------------------------------------------------------
    // Parse "HH:MM" time strings and return fractional hours between them
    // -------------------------------------------------------------------------
    function calcHours(startTime, endTime) {
        var toMins = function(t) {
            var p = t.split(':');
            return parseInt(p[0], 10) * 60 + parseInt(p[1], 10);
        };
        var diff = toMins(endTime) - toMins(startTime);
        return diff > 0 ? diff / 60 : 0;
    }

    // -------------------------------------------------------------------------
    // Show / hide time picker
    // -------------------------------------------------------------------------
    function showTimePicker() {
        if (!timePicker) { return; }
        timePicker.style.display = '';
        timePicker.removeAttribute('aria-hidden');
        if (startTimeInput) { startTimeInput.setAttribute('aria-required', 'true'); }
        if (endTimeInput)   { endTimeInput.setAttribute('aria-required', 'true'); }
    }

    function hideTimePicker() {
        if (!timePicker) { return; }
        timePicker.style.display = 'none';
        timePicker.setAttribute('aria-hidden', 'true');
        if (startTimeInput) {
            startTimeInput.value = '';
            startTimeInput.removeAttribute('aria-required');
        }
        if (endTimeInput) {
            endTimeInput.value = '';
            endTimeInput.removeAttribute('aria-required');
        }
    }

    function calcHourlyTotal(hours) {
        return hours * (data.price_per_hour || 0);
    }

    // -------------------------------------------------------------------------
    // Calculate rental days between two Date objects, honouring billing_method.
    // calendar_days: both pickup and return day are billed (diff + 1).
    // rental_nights: return day is free (diff only, minimum 1).
    // Mirrors WCRent_Utils::calc_rental_days() in PHP.
    // -------------------------------------------------------------------------
    function calcDays(start, end) {
        var msPerDay = 24 * 60 * 60 * 1000;
        var s = new Date(start.getFullYear(), start.getMonth(), start.getDate());
        var e = new Date(end.getFullYear(), end.getMonth(), end.getDate());
        var diff = Math.round((e - s) / msPerDay);
        if ( ( data.billing_method || 'calendar_days' ) === 'rental_nights' ) {
            return Math.max( 1, diff );
        }
        return diff + 1;
    }

    // -------------------------------------------------------------------------
    // Update the rental summary and hidden fields
    // -------------------------------------------------------------------------
    function updateSummary(start, end) {
        var qty  = qtyInput ? parseInt(qtyInput.value, 10) || 1 : 1;
        var days = calcDays(start, end);
        var total;
        var hourlyMode = isHourlyMode(start, end);
        var hours = hourlyMode
            && startTimeInput && endTimeInput
            && startTimeInput.value && endTimeInput.value
            ? calcHours(startTimeInput.value, endTimeInput.value)
            : 0;
        var hourly = hours > 0;

        // Always update hidden fields so the cart submission has the right dates.
        if (startHidden) startHidden.value = toYMD(start);
        if (endHidden)   endHidden.value   = toYMD(end);
        if (daysHidden)  daysHidden.value  = days;

        selectedStart = start;
        selectedEnd   = end;

        // In hourly mode, suppress the summary until the customer has entered
        // valid times — showing the daily price here would be misleading.
        if (hourlyMode && !hourly) {
            if (summaryEl) { summaryEl.classList.add('wcrent-visually-hidden'); }
            return;
        }

        if (hourly) {
            total = calcHourlyTotal(hours) * qty;
        } else {
            total = calcTotal(days) * qty;
        }

        // Summary bar
        if (summaryEl) {
            var label = summaryEl.querySelector('.wcrent-summary-text');
            if (!label) {
                label = document.createElement('span');
                label.className = 'wcrent-summary-text';
                summaryEl.appendChild(label);
            }

            if (hourly) {
                var hWord = hours === 1
                    ? (data.i18n.hour  || 'hour')
                    : (data.i18n.hours || 'hours');
                label.textContent =
                    ( data.i18n.rental_label || 'Rental' ) + ': ' +
                    formatDisplayDate(start) +
                    ' ' + startTimeInput.value + ' – ' + endTimeInput.value +
                    ' (' + hours + ' ' + hWord + ') | ' +
                    ( data.i18n.total_label || 'Total' ) + ': ' + formatCurrency(total);
            } else {
                var billingMethod = data.billing_method || 'calendar_days';
                var dayWord;
                if ( billingMethod === 'rental_nights' ) {
                    dayWord = days === 1
                        ? ( data.i18n.rental_night  || 'rental night' )
                        : ( data.i18n.rental_nights || 'rental nights' );
                } else {
                    dayWord = days === 1
                        ? ( data.i18n.calendar_day        || 'calendar day' )
                        : ( data.i18n.calendar_days_label || 'calendar days' );
                }
                label.textContent =
                    ( data.i18n.rental_label || 'Rental' ) + ': ' +
                    formatDisplayDate(start) + ' – ' + formatDisplayDate(end) +
                    ' (' + days + ' ' + dayWord + ') | ' +
                    ( data.i18n.total_label || 'Total' ) + ': ' + formatCurrency(total);
            }

            summaryEl.classList.remove( 'wcrent-visually-hidden' );
        }
    }

    // -------------------------------------------------------------------------
    // Flatpickr onChange handler
    // -------------------------------------------------------------------------
    function onDateChange(selectedDates) {
        clearError();

        if (selectedDates.length < 2) {
            // Incomplete range. Clearing unconditionally matters when a new start
            // is picked after a complete range: flatpickr reports length 1, and
            // keeping the old values would submit dates the field no longer shows.
            resetSelection();
            return;
        }

        var start = selectedDates[0];
        var end   = selectedDates[1];
        var days  = calcDays(start, end);

        var minDays = parseInt(data.min_rental_days, 10) || 1;
        var maxDays = parseInt(data.max_rental_days, 10) || 0;

        if (days < minDays) {
            showError(data.i18n.min_days_notice);
            // clear(false): a plain clear() re-enters onDateChange, which
            // starts with clearError() and would wipe the message just shown.
            if ( fpInstance ) { fpInstance.clear( false ); }
            resetSelection();
            return;
        }

        if (maxDays > 0 && days > maxDays) {
            showError( data.i18n.max_days_notice || ( 'Maximum rental period is ' + maxDays + ( maxDays === 1 ? ' day.' : ' days.' ) ) );
            if ( fpInstance ) { fpInstance.clear( false ); }
            resetSelection();
            return;
        }

        updateSummary(start, end);
        var qty = qtyInput ? parseInt(qtyInput.value, 10) || 1 : 1;
        checkAvailabilityRemote(toYMD(start), toYMD(end), qty);

        // Show or hide the hourly time picker based on whether same-day is selected.
        if (isHourlyMode(start, end)) {
            showTimePicker();
        } else {
            hideTimePicker();
        }
    }

    // -------------------------------------------------------------------------
    // Re-calculate total when quantity changes
    // -------------------------------------------------------------------------
    function onQtyChange() {
        if (selectedStart && selectedEnd) {
            updateSummary(selectedStart, selectedEnd);
            var qty = qtyInput ? parseInt(qtyInput.value, 10) || 1 : 1;
            checkAvailabilityRemote(toYMD(selectedStart), toYMD(selectedEnd), qty);
        }
    }

    // -------------------------------------------------------------------------
    // Re-calculate when time inputs change
    // -------------------------------------------------------------------------
    function onTimeChange() {
        if (!selectedStart || !selectedEnd) { return; }
        if (!isHourlyMode(selectedStart, selectedEnd)) { return; }

        var startT = startTimeInput ? startTimeInput.value : '';
        var endT   = endTimeInput   ? endTimeInput.value   : '';

        clearError();

        if (!startT || !endT) {
            // Times not fully entered yet; clear summary
            return;
        }

        if ( calcHours(startT, endT) <= 0 ) {
            showError( data.i18n.time_range_error || 'End time must be after start time.' );
            return;
        }

        updateSummary(selectedStart, selectedEnd);
        var qty = qtyInput ? parseInt(qtyInput.value, 10) || 1 : 1;
        checkAvailabilityRemote(toYMD(selectedStart), toYMD(selectedEnd), qty);
    }

    // -------------------------------------------------------------------------
    // Form submit validation
    // -------------------------------------------------------------------------
    function onFormSubmit(e) {
        if (!selectedStart || !selectedEnd) {
            e.preventDefault();
            showError( data.i18n.select_dates_error || 'Please select rental dates before adding to cart.' );
            var focusTarget = fpInstance && fpInstance.altInput ? fpInstance.altInput : inputEl;
            if ( focusTarget ) { focusTarget.focus(); }
            return;
        }

        if (isHourlyMode(selectedStart, selectedEnd)) {
            var sTime = startTimeInput ? startTimeInput.value : '';
            var eTime = endTimeInput   ? endTimeInput.value   : '';
            if (!sTime || !eTime) {
                e.preventDefault();
                showError( data.i18n.select_time_error || 'Please select start and end times for a same-day rental.' );
                if (startTimeInput && !sTime) { startTimeInput.focus(); }
                return;
            }
            if ( calcHours(sTime, eTime) <= 0 ) {
                e.preventDefault();
                showError( data.i18n.time_range_error || 'End time must be after start time.' );
                if (endTimeInput) { endTimeInput.focus(); }
                return;
            }
        }
    }

    // -------------------------------------------------------------------------
    // Initialise
    // -------------------------------------------------------------------------
    function init() {
        inputEl   = document.getElementById('wcrent-date-range');
        summaryEl = document.querySelector('.wcrent-rental-summary');
        errorEl   = document.querySelector('.wcrent-error');
        startHidden  = document.querySelector('input[name="rental_start"]');
        endHidden    = document.querySelector('input[name="rental_end"]');
        daysHidden   = document.querySelector('input[name="rental_days"]');
        qtyInput     = document.querySelector('.quantity input[type="number"], .quantity input[name="quantity"]');
        addToCartBtn   = document.querySelector('.single_add_to_cart_button');
        form           = document.querySelector('form.cart');
        timePicker     = document.getElementById('wcrent-time-picker');
        startTimeInput = document.getElementById('wcrent-start-time');
        endTimeInput   = document.getElementById('wcrent-end-time');

        if (!inputEl) {
            // Not a rental product page
            return;
        }

        // Build disabled ranges from booked dates
        var disabledRanges = buildDisabledRanges();

        fpInstance = flatpickr(inputEl, {
            mode: 'range',
            // dateFormat governs how flatpickr PARSES minDate and the disabled
            // ranges, which the server always sends as Y-m-d, so it must stay
            // Y-m-d. The admin setting is a display preference: altFormat is
            // what the customer actually sees.
            dateFormat: 'Y-m-d',
            altInput: true,
            altFormat: data.date_format || 'M j, Y',
            minDate: data.today || 'today',
            disable: disabledRanges,
            onChange: onDateChange,
            onReady: function( selectedDates, dateStr, fp ) {
                if ( fp.altInput ) {
                    fp.altInput.classList.add( 'wcrent-date-input' );
                    fp.altInput.id = 'wcrent-date-range-alt';
                    fp.altInput.setAttribute( 'aria-required', 'true' );
                    // Link to error div and min-days note for context
                    var describedBy = 'wcrent-error';
                    if ( document.getElementById( 'wcrent-min-days-note' ) ) {
                        describedBy += ' wcrent-min-days-note';
                    }
                    fp.altInput.setAttribute( 'aria-describedby', describedBy );
                }
            },
            onOpen: function( selectedDates, dateStr, fp ) {
                if ( fp.calendarContainer ) {
                    fp.calendarContainer.setAttribute( 'aria-label', data.i18n.select_dates || 'Select rental dates' );
                }
            },
            onClose: function( selectedDates, dateStr, fp ) {
                var target = fp.altInput || fp.input;
                if ( selectedDates.length > 0 && target ) { target.focus(); }
            }
        });

        // Quantity change listener
        if (qtyInput) {
            qtyInput.addEventListener('input', onQtyChange);
        }

        // Time change listeners
        if (startTimeInput) {
            startTimeInput.addEventListener('input', onTimeChange);
        }
        if (endTimeInput) {
            endTimeInput.addEventListener('input', onTimeChange);
        }

        // Form submit guard
        if (form) {
            form.addEventListener('submit', onFormSubmit);
        }

        // Hide summary initially
        if (summaryEl) summaryEl.classList.add( 'wcrent-visually-hidden' );
        clearError();
    }

    // Run after DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
