jQuery(function($) {
    // Namespace our calendar functionality
    window.EVGE = window.EVGE || {};
    window.EVGE.Calendar = window.EVGE.Calendar || {};

    /**
     * Increment refresh generation on a calendar wrapper (invalidates in-flight AJAX for that block).
     * Cancels a pending loading fade-out timer from a previous completion.
     *
     * @param {JQuery} $wrapper .evge-calendar-wrapper
     * @returns {number} generation id for this request
     */
    window.EVGE.Calendar.bumpRefreshGeneration = function($wrapper) {
        if (!$wrapper || !$wrapper.length) {
            return 0;
        }
        const prevTimer = $wrapper.data('evgeCalLoadingEndTimer');
        if (prevTimer) {
            clearTimeout(prevTimer);
            $wrapper.removeData('evgeCalLoadingEndTimer');
        }
        $wrapper.removeClass('evge-loading--exiting');
        const n = ($wrapper.data('evgeCalRefreshGen') || 0) + 1;
        $wrapper.data('evgeCalRefreshGen', n);
        return n;
    };

    /**
     * @param {JQuery} $wrapper
     * @param {number} myGen value from bumpRefreshGeneration when this request started
     * @returns {boolean} true if a newer refresh superseded this one
     */
    window.EVGE.Calendar.isStaleRefresh = function($wrapper, myGen) {
        if (!$wrapper || !$wrapper.length) {
            return true;
        }
        return ($wrapper.data('evgeCalRefreshGen') || 0) !== myGen;
    };

    /**
     * Fade the loading overlay out, then remove .evge-loading (matches .evge-loading--exiting in evge-calendar.css).
     *
     * @param {JQuery} $wrapper .evge-calendar-wrapper
     * @param {function(): void} [done]
     * @returns {number|undefined} timeout id (for tests / cancellation via bumpRefreshGeneration)
     */
    window.EVGE.Calendar.endLoadingSmooth = function($wrapper, done) {
        const ms = 230;
        if (!$wrapper || !$wrapper.length) {
            if (typeof done === 'function') {
                done();
            }
            return undefined;
        }
        if (!$wrapper.hasClass('evge-loading')) {
            if (typeof done === 'function') {
                done();
            }
            return undefined;
        }
        const prev = $wrapper.data('evgeCalLoadingEndTimer');
        if (prev) {
            clearTimeout(prev);
        }
        $wrapper.addClass('evge-loading--exiting');
        const timer = setTimeout(function() {
            $wrapper.removeData('evgeCalLoadingEndTimer');
            $wrapper.removeClass('evge-loading evge-loading--exiting');
            if (typeof done === 'function') {
                done();
            }
        }, ms);
        $wrapper.data('evgeCalLoadingEndTimer', timer);
        return timer;
    };

    // One document listener closes month dropdowns for all calendar instances (outside click).
    (function bindMonthDropdownOutsideClose() {
        if (window.EVGE.Calendar._monthDropdownOutsideBound) {
            return;
        }
        window.EVGE.Calendar._monthDropdownOutsideBound = true;
        $(document).on('click.evgeCalendarMonthDropdown', function(e) {
            $('.evge-calendar-wrapper').each(function() {
                const $w = $(this);
                const $selector = $w.find('.evge-month-selector');
                if (!$selector.length) {
                    return;
                }
                if ($(e.target).closest($selector).length) {
                    return;
                }
                $w.find('.evge-month-dropdown').removeClass('evge-active');
            });
        });
    })();

    // Expand hidden secondary search matches (same button pattern as series load-more; separate class avoids series AJAX).
    (function bindCalendarSecondarySearchShowAll() {
        if (window.EVGE.Calendar._secondarySearchShowAllBound) {
            return;
        }
        window.EVGE.Calendar._secondarySearchShowAllBound = true;
        $(document).on('click.evgeCalendarSecondarySearch', '.evge-calendar-secondary-show-all', function(e) {
            e.preventDefault();
            const $btn = $(e.target).closest('.evge-calendar-secondary-show-all');
            const $more = $btn.closest('.evge-series-events-load-more').prev('.evge-calendar-secondary-search-more');
            if ($more.length) {
                $more.removeClass('evge-hidden').attr('aria-hidden', 'false');
            }
            $btn.closest('.evge-series-events-load-more').remove();
        });
    })();

    // Calendar class — pass a single `.evge-calendar-wrapper` jQuery object so multiple calendars on one page stay isolated.
    window.EVGE.Calendar.EventCalendar = class {
        constructor($wrapper) {
            this.container = $wrapper && $wrapper.jquery ? $wrapper.first() : $($wrapper).first();
            if (!this.container.length) {
                return;
            }

            // Get current date from data attribute
            const currentMonth = this.container.data('currentMonth');
            this.currentDate = currentMonth ? new Date(currentMonth + '-03') : new Date();

            this.tooltip = this.container.find('.evge-event-tooltip');
            this.currentView = this.container.find('.evge-view-select').val() || this.container.data('view') || 'list';

            this.toolTipCache = {};
            this.eventCache = new Map();
            this.dayEventsCache = new Map();

            this.pendingTooltips = new Set();

            // Store initial filter values as defaults
            const $listSort = this.container.find('.evge-list-sort-select');
            this.defaultFilters = {
                search: this.container.find('.evge-search-input').val() || '',
                venue_id: this.container.find('.evge-venue-select').val() || '',
                time_filter: this.container.find('.evge-time-select').val() || 'upcoming',
                list_sort_order: $listSort.length ? ($listSort.val() || '') : '',
                view: this.container.find('.evge-view-select').val() || this.container.data('view') || 'list',
                paged: parseInt(this.container.data('paged')) || 1
            };

            this.init();
        }

        init() {
            if (!this.container.length) {
                return;
            }
            this.dayEventsCalendar = this.container.find('.evge-day-events-calendar');

            this.initializeEventListeners();
            this.initializeResizeObserver();

            const $yearDisplay = this.container.find('.evge-year-display');
            if ($yearDisplay.length) {
                $yearDisplay.text(this.currentDate.getFullYear());
            }
        }

        initializeEventListeners() {
            if (!this.container.length) return;

            // Remove any existing event listeners
            this.container.off();

            // Filter bar: action points at the current page; submission is handled via AJAX (no full page reload).
            this.container.on('submit', '.evge-filter-bar-form', (e) => {
                e.preventDefault();
                this.container.attr('data-paged', 1);
                const currentFilters = this.getCurrentFilters();
                currentFilters.paged = 1;
                this.updateUrlParams(currentFilters);
                this.refreshCalendar(currentFilters);
            });

            // Add show more events handler
            this.container.on('click', '.evge-show-more-events', (e) => {
                const $calendarDay = $(e.target).closest('.evge-calendar-day');
                $calendarDay.toggleClass('evge-show-all-events');

                $calendarDay.find('.evge-event-card').removeClass('evge-event-hidden');

                // If we're hiding events, scroll back to top of day
                if (!$calendarDay.hasClass('evge-show-all-events')) {
                    $calendarDay[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
                }
            });

            // Show more filters when "..." button is clicked
            this.container.on('click', '.evge-filter-more-button', (e) => {
                e.preventDefault();
                $(e.currentTarget).closest('.evge-filter-group').addClass('evge-filter-group-expanded');
            });

            // Handle no events found buttons
            this.container.on('click', '.evge-clear-search', () => {
                // Clear search input
                this.container.find('.evge-search-input').val('');
                // Clear any active filters
                this.container.find('.evge-filter-active').removeClass('evge-filter-active');
                // Trigger calendar refresh
                this.refreshCalendar({
                    search: '',
                    paged: 1
                });
            });

            this.container.on('click', '.evge-clear-filters', () => {
                // Clear any active filters
                this.container.find('.evge-filter-active').removeClass('evge-filter-active');
                // Reset all filter inputs
                this.container.find('.evge-venue-select').val('');
                this.container.find('.evge-time-select').val('upcoming');
                const $ls = this.container.find('.evge-list-sort-select');
                if ($ls.length) {
                    $ls.val('asc');
                }
                this.container.find('.evge-search-input').val('');
                // Trigger calendar refresh
                this.refreshCalendar({
                    search: '',
                    venue_id: '',
                    time_filter: 'upcoming',
                    list_sort_order: $ls.length ? 'asc' : '',
                    paged: 1
                });
            });

            this.container.on('click', '.evge-view-all', () => {
                // Clear all filters and search
                this.container.find('.evge-search-input').val('');
                this.container.find('.evge-filter-active').removeClass('evge-filter-active');
                // Set time filter to 'all' to show all events
                this.container.find('.evge-time-select').val('all');
                this.container.find('.evge-venue-select').val('');
                const $lsAll = this.container.find('.evge-list-sort-select');
                if ($lsAll.length) {
                    $lsAll.val('desc');
                }
                // Trigger calendar refresh with all events and reset filters
                this.refreshCalendar({
                    search: '',
                    time_filter: 'all',
                    list_sort_order: $lsAll.length ? 'desc' : '',
                    venue_id: '',
                    paged: 1
                });
            });

            // Search input with debounce
            let searchTimeout;
            this.container.on('input', '.evge-search-input', (e) => {
                clearTimeout(searchTimeout);
                searchTimeout = setTimeout(() => {
                    // Reset page number and update URL
                    this.container.attr('data-paged', 1);
                    const currentFilters = this.getCurrentFilters();
                    currentFilters.paged = 1;
                    this.updateUrlParams(currentFilters);
                    
                    this.refreshCalendar(currentFilters);
                }, 500);
            });

            // Venue select
            this.container.on('change', '.evge-venue-select', (e) => {
                // Reset page number and update URL
                this.container.attr('data-paged', 1);
                const currentFilters = this.getCurrentFilters();
                currentFilters.paged = 1;
                this.updateUrlParams(currentFilters);
                
                this.refreshCalendar(currentFilters);
            });

            // Category select
            this.container.on('change', '.evge-category-select', (e) => {
                // Reset page number and update URL
                this.container.attr('data-paged', 1);
                const currentFilters = this.getCurrentFilters();
                currentFilters.paged = 1;
                this.updateUrlParams(currentFilters);
                
                this.refreshCalendar(currentFilters);
            });

            // Tag select
            this.container.on('change', '.evge-tag-select', (e) => {
                // Reset page number and update URL
                this.container.attr('data-paged', 1);
                const currentFilters = this.getCurrentFilters();
                currentFilters.paged = 1;
                this.updateUrlParams(currentFilters);
                
                this.refreshCalendar(currentFilters);
            });

            // Time filter select
            this.container.on('change', '.evge-time-select', (e) => {
                // Reset page number and update URL
                this.container.attr('data-paged', 1);
                const currentFilters = this.getCurrentFilters();
                currentFilters.paged = 1;
                this.updateUrlParams(currentFilters);
                
                this.refreshCalendar(currentFilters);
            });

            // List sort order select
            this.container.on('change', '.evge-list-sort-select', (e) => {
                this.container.attr('data-paged', 1);
                const currentFilters = this.getCurrentFilters();
                currentFilters.paged = 1;
                this.updateUrlParams(currentFilters);
                
                this.refreshCalendar(currentFilters);
            });

            // View select
            const $viewSelect = this.container.find('.evge-view-select');
            if ($viewSelect.length) {
                $viewSelect.val(this.currentView);

                this.container.on('change', '.evge-view-select', (e) => {
                    this.currentView = e.target.value;
                    // Update the data-view attribute on the wrapper
                    this.container.attr('data-view', e.target.value);
                    
                    // Hide any events listed below the calendar (mobile view)
                    if (this.dayEventsCalendar && this.dayEventsCalendar.length) {
                        this.dayEventsCalendar.hide();
                    }
                    
                    // Reset page number and update URL
                    this.container.attr('data-paged', 1);
                    const currentFilters = this.getCurrentFilters();
                    currentFilters.paged = 1;
                    this.updateUrlParams(currentFilters);
                    this.refreshCalendar(currentFilters);
                });
            }

            // Month selector (delegated so re-renders do not stack duplicate handlers)
            this.container.on('click', '.evge-month-calendar-month-name', (e) => {
                e.stopPropagation();
                const $dropdown = this.container.find('.evge-month-dropdown');
                const $yearDisplay = this.container.find('.evge-year-display');
                if (!$yearDisplay.text().trim()) {
                    $yearDisplay.text(this.currentDate.getFullYear());
                }
                $dropdown.toggleClass('evge-active');
                if ($dropdown.hasClass('evge-active')) {
                    this.updateMonthDropdownHighlight();
                }
            });

            this.container.on('click', '.evge-year-prev', (e) => {
                e.stopPropagation();
                const $yearDisplay = this.container.find('.evge-year-display');
                let y = parseInt($yearDisplay.text(), 10);
                if (isNaN(y)) {
                    y = this.currentDate.getFullYear();
                }
                y--;
                $yearDisplay.text(y);
                this.updateMonthDropdownHighlight();
            });

            this.container.on('click', '.evge-year-next', (e) => {
                e.stopPropagation();
                const $yearDisplay = this.container.find('.evge-year-display');
                let y = parseInt($yearDisplay.text(), 10);
                if (isNaN(y)) {
                    y = this.currentDate.getFullYear();
                }
                y++;
                $yearDisplay.text(y);
                this.updateMonthDropdownHighlight();
            });

            this.container.on('click', '.evge-month-grid', async (e) => {
                const $monthOption = $(e.target).closest('.evge-month-option');
                if (!$monthOption.length) {
                    return;
                }
                const $yearDisplay = this.container.find('.evge-year-display');
                const month = $monthOption.data('month').toString().padStart(2, '0');
                const year = $yearDisplay.text();
                const selectedDate = `${year}-${month}`;

                await this.refreshCalendar({ selectedDate: selectedDate });
                this.container.find('.evge-month-dropdown').removeClass('evge-active');
            });

            // Navigation
            this.container.on('click', '.evge-nav-button', (e) => {
                const $button = $(e.target).closest('.evge-nav-button');
                this.handleNavigation(e, $button);
            });

            // Event tooltips
            this.initializeTooltips();

            // More events popup
            this.container.on('click', '.evge-more-events', (e) => this.showMoreEvents(e));


            // Day click handler for narrow view
            this.container.on('click', '.evge-calendar-day.evge-has-events', async (e) => {
                if (!this.container.hasClass('evge-calendar-narrow')) return;

                const $calendarDay = $(e.target).closest('.evge-calendar-day');
                if (!$calendarDay.length) return;

                const date = $calendarDay.data('date');

                // Remove any existing day events calendar
                // Load and display events for this day
                await this.loadDayEvents(date, $calendarDay);
            });
        }

        updateMonthDropdownHighlight() {
            const currentMonth = this.currentDate.getMonth() + 1;
            const $yearDisplay = this.container.find('.evge-year-display');
            const displayedYear = parseInt($yearDisplay.text(), 10);
            if (isNaN(displayedYear)) {
                return;
            }

            this.container.find('.evge-month-option').each((i, option) => {
                const $option = $(option);
                if (parseInt($option.data('month'), 10) === currentMonth && this.currentDate.getFullYear() === displayedYear) {
                    $option.addClass('evge-active');
                } else {
                    $option.removeClass('evge-active');
                }
            });
        }

        async handleNavigation(e, $button) {
            const action = $button.data('action');
            await this.refreshCalendar({ direction: action });
        }

        initializeTooltips() {
            // Initialize Tooltipster on event cards (each calendar uses its own tooltip container)
            const $tooltipContent = this.container.find('.evge-tooltipster-container').first();
            this.container.find('.evge-event-card').tooltipster({
                content: $tooltipContent.length ? $tooltipContent : this.container.find('.evge-event-tooltip'),
                contentAsHTML: true,
                interactive: true,
                contentCloning: true,
                animation: 'fade',
                delay: 200,
                functionBefore: (instance, helper) => {
                    const eventId = $(helper.origin).data('eventId');
                    if (!eventId) {
                        console.error('No event ID found on card');
                        return false;
                    }

                    // Load the actual content when tooltip is about to be shown
                    this.loadEventTooltip(eventId, instance);
                    return true; // Allow the tooltip to be shown
                },
            });
        }

        async loadEventTooltip(eventId, tooltipsterInstance) {
            try {
                let tooltipContent;

                // Check cache first
                if (this.eventCache.has(eventId)) {
                    tooltipContent = this.eventCache.get(eventId);
                } else {
                    // If not in cache, fetch and store
                    const response = await this.fetchCalendarData(
                        this.getAjaxParams(this.container, {
                            action: 'evge_get_event_details',
                            includeFilters: true,
                            overrides: { event_id: eventId }
                        })
                    );

                    if (response.success && response.data) {
                        tooltipContent = response.data.html;
                        this.eventCache.set(eventId, tooltipContent);
                    } else {
                        throw new Error('Invalid response format');
                    }
                }

                // Update the tooltip content
                if (tooltipsterInstance) {
                    tooltipsterInstance.content(tooltipContent);
                    if (window.Evge && window.Evge.Modal && window.Evge.Modal.initTriggers) {
                        setTimeout(() => {
                            window.Evge.Modal.initTriggers();
                        }, 100);
                    }
                    
                    // Sync bulk registration button state if event is already selected
                    if (window.EVGE && window.EVGE.BulkRegistration && window.EVGE.BulkRegistration.Panel) {
                        setTimeout(() => {
                            // Find the select button in the tooltip content
                            // Tooltipster stores content in .evge-event-tooltip within .evge-tooltipster-base
                            const $selectButton = $('.evge-tooltipster-base .evge-bulk-select-button');
                            if ($selectButton.length) {
                                const eventId = $selectButton.data('evge-event-id');
                                if (eventId && window.EVGE.BulkRegistration.Panel.selectedEvents[eventId]) {
                                    // Event is already selected, update button state
                                    $selectButton.addClass('evge-selected');
                                    const selectedText = $selectButton.data('selected-text');
                                    if (selectedText) {
                                        $selectButton.text(selectedText);
                                    } else {
                                        $selectButton.text('Selected');
                                    }
                                }
                            }
                        }, 150);
                    }
                }
            } catch (error) {
                console.error('Error loading event tooltip:', error);
                if (tooltipsterInstance) {
                    tooltipsterInstance.content(`
                        <div class="evge-event-list-item">
                            <h3>Error loading event details</h3>
                            <p>Please try again later</p>
                        </div>
                    `);
                }
            }
        }

        showMoreEvents(e) {
            const $day = $(e.target).closest('.evge-calendar-day');
            const date = $day.data('date');
            // Implementation for showing more events popup
            // This could be another AJAX call or reveal hidden events
        }

        async fetchCalendarData(data) {
            try {                
                const response = await window.Evge.ajax({
                    data: data
                });
                return response;
            } catch (error) {
                console.error('Calendar AJAX error:', error);
                return { success: false };
            }
        }

        updateCalendar(html, currentDateDisplay) {
            const $tempDiv = $('<div>').html(html);
            const currentDate = this.currentDate;
            
            if (this.currentView === 'month') {
                this.container.find('.evge-month-calendar-top').show();
            } else {
                this.container.find('.evge-month-calendar-top').hide();
            }

            this.container.find('.evge-ajax-content').replaceWith(
                $tempDiv.find('.evge-ajax-content')
            );

            // Initialize tooltips in new content
            this.initializeTooltips();

            // Re-initialize modal triggers for the newly loaded content
            if (window.Evge && window.Evge.Modal && window.Evge.Modal.initTriggers) {
                setTimeout(() => {
                    window.Evge.Modal.initTriggers();
                }, 100);
            }

            // Update active month in dropdown
            const currentMonth = this.currentDate.getMonth() + 1;
            this.container.find('.evge-month-option').each((i, option) => {
                const $option = $(option);
                if (parseInt($option.data('month')) === currentMonth) {
                    $option.addClass('evge-active');
                } else {
                    $option.removeClass('evge-active');
                }
            });

            // Update year display
            const $yearDisplay = this.container.find('.evge-year-display');
            if ($yearDisplay.length) {
                $yearDisplay.text(currentDate.getFullYear());
            }
        }

        positionTooltip($eventCard) {
            if (!this.tooltip.length || !$eventCard.length) return;

            $eventCard.append( this.tooltip );

            //Determine whether to show the tooltip to the left or right of card
            var containerWidth = this.container.width(),
                $calDay = $eventCard.closest('.evge-calendar-day'),
                cardWidth = $calDay.innerWidth(),
                cardIndex = $calDay.index()+1,
                roomToEdge = containerWidth - (cardIndex * cardWidth),
                rightVal = (7-cardIndex) * cardWidth;

            if( roomToEdge < this.tooltip.width() ){
                this.tooltip.css({'right' : -rightVal, 'left' : 'auto'});
            } else {
                this.tooltip.css({'left' : 0, 'right' : 'auto'});
            }
        }

        async refreshCalendar(params = {}) {
            if (!this.container.length) {
                return;
            }

            const myGen = window.EVGE.Calendar.bumpRefreshGeneration(this.container);

            try {
                // Hide any events listed below the calendar (mobile view)
                if (this.dayEventsCalendar && this.dayEventsCalendar.length) {
                    this.dayEventsCalendar.hide();
                }

                const $eventCalendar = this.container.find('.evge-event-calendar');
                const $dynamicContent = this.container.find('.evge-calendar-dynamic-content');

                // Store the current height
                const currentHeight = $eventCalendar.height();
                $eventCalendar.css('height', currentHeight + 'px');

                this.container.addClass('evge-loading');

                // Brief pause so CSS fade-in can start before the request (reduced from 300ms now that overlay animates)
                await new Promise(resolve => setTimeout(resolve, 100));

                if (window.EVGE.Calendar.isStaleRefresh(this.container, myGen)) {
                    return;
                }

                const response = await this.fetchCalendarData(
                    this.getAjaxParams(null, {
                        action: 'evge_calendar_navigation',
                        overrides: params
                    })
                );

                if (window.EVGE.Calendar.isStaleRefresh(this.container, myGen)) {
                    return;
                }

                if (response.success) {
                    // Insert new content while maintaining height
                    $dynamicContent.html(response.data.html);

                    // Get the new height and animate to it
                    const newHeight = $dynamicContent.height();
                    $eventCalendar.css('height', newHeight + 'px');

                    this.currentDate = new Date(response.data.current_date + '-03');

                    // Update URL with current filters
                    const currentFilters = this.getCurrentFilters();
                    this.updateUrlParams(currentFilters);

                    this.init();

                    // Re-initialize modal triggers for the newly loaded content
                    if (window.Evge && window.Evge.Modal && window.Evge.Modal.initTriggers) {
                        setTimeout(() => {
                            window.Evge.Modal.initTriggers();
                        }, 100);
                    }

                    const self = this;
                    window.EVGE.Calendar.endLoadingSmooth(this.container, function() {
                        if (window.EVGE.Calendar.isStaleRefresh(self.container, myGen)) {
                            return;
                        }
                        self.container.find('.evge-event-card').addClass('evge-visible');
                        $eventCalendar.css('height', '');
                    });
                } else {
                    window.EVGE.Calendar.endLoadingSmooth(this.container, () => {
                        if (window.EVGE.Calendar.isStaleRefresh(this.container, myGen)) {
                            return;
                        }
                        $eventCalendar.css('height', '');
                    });
                }
            } catch (error) {
                if (!window.EVGE.Calendar.isStaleRefresh(this.container, myGen)) {
                    window.EVGE.Calendar.endLoadingSmooth(this.container, () => {
                        this.container.find('.evge-event-calendar').css('height', '');
                    });
                }
            }
        }

        initializeResizeObserver() {
            if (!this.container.length) return;

            // preserve the preview
            if ($('.evge-calendar-builder').length) {
                return;
            }

            const resizeObserver = new ResizeObserver(entries => {
                for (const entry of entries) {
                    const width = entry.contentRect.width;
                    this.container.toggleClass('evge-calendar-narrow', width < 800);
                    this.container.toggleClass('evge-calendar-super-narrow', width < 500);
                }
            });

            resizeObserver.observe(this.container[0]);
        }

        async loadDayEvents(date, $calendarDay) {
            let events;

            if (this.dayEventsCache.has(date)) {
                events = this.dayEventsCache.get(date);
            } else {
                const response = await this.fetchCalendarData(
                    this.getAjaxParams($calendarDay.closest('.evge-calendar-wrapper'), {
                        action: 'evge_get_day_events',
                        includeFilters: true,
                        overrides: { date: date }
                    })
                );

                if (response.success) {
                    events = response.data.html;
                    this.dayEventsCache.set(date, events);
                }
            }

            if (events) {
                this.dayEventsCalendar.html(events).show();
                this.dayEventsCalendar[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });

                // Re-initialize modal triggers for the newly loaded day events
                if (window.Evge && window.Evge.Modal && window.Evge.Modal.initTriggers) {
                    setTimeout(() => {
                        window.Evge.Modal.initTriggers();
                    }, 100);
                }

                // Sync bulk registration button states if events are already selected
                if (window.EVGE && window.EVGE.BulkRegistration && window.EVGE.BulkRegistration.Panel) {
                    setTimeout(() => {
                        const $selectButtons = this.dayEventsCalendar.find('.evge-bulk-select-button');
                        $selectButtons.each((index, button) => {
                            const $button = $(button);
                            const eventId = $button.data('evge-event-id');
                            if (eventId && window.EVGE.BulkRegistration.Panel.selectedEvents[eventId]) {
                                // Event is already selected, update button state
                                $button.addClass('evge-selected');
                                const selectedText = $button.data('selected-text');
                                if (selectedText) {
                                    $button.text(selectedText);
                                } else {
                                    $button.text('Selected');
                                }
                            }
                        });
                    }, 150);
                }
            }
        }

        /**
         * Get standardized parameters for AJAX calls
         * @param {Object} $context - jQuery element to get context from (defaults to container)
         * @param {Object} options - Configuration options
         * @param {string} options.action - The AJAX action to call (e.g., 'evge_calendar_navigation', 'evge_get_event_details')
         * @param {Object} options.overrides - Optional overrides for any parameters
         * @param {boolean} options.includeFilters - Whether to include filter parameters (default: true)
         * @returns {Object} Standardized parameters for AJAX calls
         */
        getAjaxParams($context = null, options = {}) {
            // Use provided context or fall back to container
            const $target = $context || this.container;
            
            // Default options
            const defaults = {
                action: 'evge_calendar_navigation',
                includeFilters: true,
                overrides: {}
            };
            
            // Merge provided options with defaults
            const config = { ...defaults, ...options };
            
            // Start with base parameters
            const params = {
                action: config.action,
            };

            // Add filter parameters if requested
            if (config.includeFilters) {
                const $sortSelect = $target.find('.evge-list-sort-select');
                const resolvedDate =
                    this.currentDate instanceof Date && !isNaN(this.currentDate.getTime())
                        ? this.currentDate
                        : new Date();
                Object.assign(params, {
                    current_date: $target.data('current-date') || resolvedDate.toISOString().slice(0, 7),
                    view: $target.find('.evge-view-select').val() || $target.data('view') || this.currentView || 'list',
                    month: $target.data('month') || '',
                    search: $target.find('.evge-search-input').val() || '',
                    venue_id: $target.find('.evge-venue-select').val() || '',
                    time_filter: $target.find('.evge-time-select').val() || 'upcoming',
                    list_sort_order: $sortSelect.length ? ($sortSelect.val() || '') : '',
                    paged: $target.data('paged') || 1,
                    calendar_id: $target.data('calendar-id') || '',
                    category_id: $target.find('.evge-category-select').val() || '',
                    tag_id: $target.find('.evge-tag-select').val() || '',
                    date: ''
                });
            }

            const merged = { ...params, ...config.overrides };

            // Event tag/category archives hide the dropdowns; overrides may still send empty tag_id/category_id.
            if (config.includeFilters) {
                const archTag = $target.data('archiveTagId');
                const archCat = $target.data('archiveCategoryId');
                if ((!merged.tag_id || merged.tag_id === '') && archTag != null && archTag !== '') {
                    merged.tag_id = String(archTag);
                }
                if ((!merged.category_id || merged.category_id === '') && archCat != null && archCat !== '') {
                    merged.category_id = String(archCat);
                }
            }

            return merged;
        }

        /**
         * Get current filter values from the form
         * @returns {Object} Current filter values
         */
        getCurrentFilters() {
            const $sort = this.container.find('.evge-list-sort-select');
            const catVal = this.container.find('.evge-category-select').val() || '';
            const tagVal = this.container.find('.evge-tag-select').val() || '';
            const archCat = this.container.data('archiveCategoryId');
            const archTag = this.container.data('archiveTagId');
            return {
                search: this.container.find('.evge-search-input').val() || '',
                venue_id: this.container.find('.evge-venue-select').val() || '',
                category_id: catVal || (archCat != null && archCat !== '' ? String(archCat) : ''),
                tag_id: tagVal || (archTag != null && archTag !== '' ? String(archTag) : ''),
                time_filter: this.container.find('.evge-time-select').val() || 'upcoming',
                list_sort_order: $sort.length ? ($sort.val() || '') : '',
                view: this.container.find('.evge-view-select').val() || this.container.data('view') || 'list',
                paged: parseInt(this.container.data('paged')) || 1
            };
            
        }

        /**
         * Check if current filters match default values
         * @param {Object} filters Current filter values
         * @returns {boolean} True if filters match defaults
         */
        isDefaultFilters(filters) {
            return Object.keys(this.defaultFilters).every(key => 
                filters[key] === this.defaultFilters[key]
            );
        }

        /**
         * Query-string prefix for this calendar. When several calendars share a page and each has a
         * `data-calendar-id`, keys are namespaced so instances do not overwrite each other's URL state.
         */
        /**
         * When several calendars share a page, append this wrapper's id as the URL hash so visitors
         * can see which block was last updated (and deep links scroll to it on load).
         */
        getCalendarUrlHashFragment() {
            if ($('.evge-calendar-wrapper').length <= 1) {
                return '';
            }
            const wrapperId = this.container.attr('id');
            return wrapperId ? '#' + wrapperId : '';
        }

        getUrlQueryKeyPrefix() {
            const multi = $('.evge-calendar-wrapper').length > 1;
            if (!multi) {
                return 'evge_';
            }
            const id = this.container.data('calendar-id');
            if (id !== undefined && id !== null && String(id) !== '') {
                return 'evge_cal_' + id + '_';
            }
            return 'evge_';
        }

        /**
         * Update URL query parameters based on current filters
         * @param {Object} filters Current filter values
         */
        updateUrlParams(filters) {
            const url = new URL(window.location.href);
            const params = new URLSearchParams(url.search);
            const keyPrefix = this.getUrlQueryKeyPrefix();

            if (keyPrefix === 'evge_') {
                for (const key of [...params.keys()]) {
                    if (key.startsWith('evge_')) {
                        params.delete(key);
                    }
                }
                Object.entries(filters).forEach(([key, value]) => {
                    params.set('evge_' + key, encodeURIComponent(value));
                });
            } else {
                for (const key of [...params.keys()]) {
                    if (key.startsWith(keyPrefix)) {
                        params.delete(key);
                    }
                }
                Object.entries(filters).forEach(([key, value]) => {
                    params.set(keyPrefix + key, encodeURIComponent(value));
                });
            }

            // Update URL with new params (and hash when multiple calendars, to highlight the active block)
            const newUrl = url.pathname + (params.toString() ? '?' + params.toString() : '') + this.getCalendarUrlHashFragment();
            window.history.replaceState({}, '', newUrl);
        }
    };

    // Calendar initializer
    window.EVGE.Calendar.Initializer = {
        init: function() {
            if (!this.checkDependencies()) return;
            window.EVGE.Hooks.addAction('evge_page_created', this.handlePageCreated.bind(this));
        },

        checkDependencies: function() {
            if (typeof window.EVGE.Hooks === 'undefined') {
                console.error('EVGE Calendar: Required dependencies not loaded');
                return false;
            }
            return true;
        },

        handlePageCreated: function() {
            $('.evge-calendar-wrapper').each(function() {
                new window.EVGE.Calendar.EventCalendar($(this));
            });
            window.EVGE.Calendar.Initializer.scrollToCalendarFromHash();
        },

        /**
         * If the URL fragment matches a calendar wrapper id, scroll it into view (e.g. shared links with #evge-calendar-…).
         */
        scrollToCalendarFromHash: function() {
            const hash = window.location.hash;
            if (!hash || hash.length < 2) {
                return;
            }
            const id = decodeURIComponent(hash.slice(1));
            if (!id || id.indexOf('evge-calendar-') !== 0) {
                return;
            }
            const el = document.getElementById(id);
            if (!el || !el.classList.contains('evge-calendar-wrapper')) {
                return;
            }
            requestAnimationFrame(function() {
                el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
            });
        }
    };

    // Initialize the calendar functionality
    window.EVGE.Calendar.Initializer.init();

    // Handle pagination clicks
    $(document).on('click', '.evge-pagination a', function(e) {
        e.preventDefault();
        
        const $container = $(this).closest('.evge-calendar-wrapper');
        const page = $(this).data('page');
        const $pagination = $(this).closest('.evge-pagination');

        // If this is archive pagination, let WordPress handle it normally
        if ($pagination.hasClass('evge-archive-pagination')) {
            window.location.href = $(this).attr('href');
            return;
        }

        // Pagination outside a calendar wrapper (e.g. My Registrations) must use full navigation — same markup as calendar AJAX pagination.
        if (!$container.length) {
            window.location.href = $(this).attr('href');
            return;
        }

        if ($container.hasClass('evge-loading')) {
            return;
        }

        const myGen = window.EVGE.Calendar.bumpRefreshGeneration($container);
        $container.addClass('evge-loading');

        // Get standardized parameters and add pagination specific ones
        const eventCalendar = new window.EVGE.Calendar.EventCalendar($container);
        const ajaxParams = eventCalendar.getAjaxParams($container, {
            overrides: {
                direction: '',
                paged: page
            }
        });

        // Make AJAX request
        window.Evge.ajax({
            data: ajaxParams,
            success: function(response) {
                if (window.EVGE.Calendar.isStaleRefresh($container, myGen)) {
                    return;
                }
                if (response.success) {
                    // Update the content
                    $container.find('.evge-events-archive-main').html(response.data.html);
                    
                    // Update data attributes
                    $container.attr('data-current-date', response.data.current_date);
                    $container.attr('data-view', ajaxParams.view);
                    $container.attr('data-month', ajaxParams.month);
                    $container.attr('data-paged', page);

                    // Update URL with new page number
                    const currentFilters = eventCalendar.getCurrentFilters();
                    currentFilters.paged = page;
                    eventCalendar.updateUrlParams(currentFilters);

                    // Re-initialize modal triggers for the newly loaded content
                    if (window.Evge && window.Evge.Modal && window.Evge.Modal.initTriggers) {
                        setTimeout(() => {
                            window.Evge.Modal.initTriggers();
                        }, 100);
                    }

                    // Scroll to top of event listings
                    const $eventsArchive = $container.find('.evge-events-archive-main');
                    if ($eventsArchive.length) {
                        $('html, body').animate({
                            scrollTop: $eventsArchive.offset().top - 100
                        }, 300);
                    }
                }
            },
            complete: function() {
                if (window.EVGE.Calendar.isStaleRefresh($container, myGen)) {
                    return;
                }
                window.EVGE.Calendar.endLoadingSmooth($container);
            }
        });
    });
}); 