/**
 * Find Training Map - Google Maps Integration
 *
 * Handles Google Maps initialization, markers, clustering,
 * and interaction for the Find Training page.
 *
 * @package HVAC_Community_Events
 * @since 2.2.0
 */

(function($) {
    'use strict';

    // Namespace for the module
    window.HVACTrainingMap = {

        // Map instance
        map: null,

        // Marker collections
        trainerMarkers: [],
        venueMarkers: [],
        eventMarkers: [],

        // MarkerClusterer instance
        markerClusterer: null,

        // Info window instance (reused)
        infoWindow: null,

        // Current data
        trainers: [],
        venues: [],
        events: [],

        // Visible items (filtered by map bounds)
        visibleTrainers: [],
        visibleVenues: [],
        visibleEvents: [],

        // Active tab
        activeTab: 'events',

        // Items per page for load more
        itemsPerPage: 6,
        displayedCounts: {
            trainers: 0,
            venues: 0,
            events: 0
        },

        // Configuration
        config: {
            mapElementId: 'hvac-training-map',
            defaultCenter: { lat: 39.8283, lng: -98.5795 },
            defaultZoom: 4,
            clusterZoom: 8
        },

        /**
         * Initialize the map
         */
        init: function() {
            const self = this;

            // Check if API key is configured
            if (typeof hvacFindTraining === 'undefined' || !hvacFindTraining.api_key_configured) {
                console.warn('Google Maps API key not configured');
                // Initialize tabs even without map
                this.initTabs();
                // Still load trainer directory data
                this.loadTrainerDirectory();
                return;
            }

            // Check if Google Maps is loaded
            if (typeof google === 'undefined' || typeof google.maps === 'undefined') {
                console.error('Google Maps API not loaded');
                this.showMapError('Google Maps failed to load. Please refresh the page.');
                // Initialize tabs even without map
                this.initTabs();
                // Still load trainer directory data
                this.loadTrainerDirectory();
                return;
            }

            // Override config with localized data
            if (hvacFindTraining.map_center) {
                this.config.defaultCenter = hvacFindTraining.map_center;
            }
            if (hvacFindTraining.default_zoom) {
                this.config.defaultZoom = parseInt(hvacFindTraining.default_zoom);
            }

            // Create the map
            this.createMap();

            // Create info window
            this.infoWindow = new google.maps.InfoWindow();

            // Load initial data
            this.loadMapData();

            // Bind events
            this.bindEvents();

            // Initialize tabs
            this.initTabs();

            // Initialize responsive features
            this.handleWindowResize();
            this.initSidebarToggle();

        },

        /**
         * Load just the trainer directory (no map)
         */
        loadTrainerDirectory: function() {
            const self = this;

            $.ajax({
                url: hvacFindTraining.ajax_url,
                type: 'POST',
                data: {
                    action: 'hvac_get_training_map_data',
                    nonce: hvacFindTraining.nonce
                },
                success: function(response) {
                    if (response.success && response.data) {
                        self.trainers = response.data.trainers || [];
                        self.venues = response.data.venues || [];
                        self.events = response.data.events || [];

                        // Sort trainers: non-champions first, champions last, then by name
                        self.trainers.sort(function(a, b) {
                            if (a.is_champion !== b.is_champion) {
                                return a.is_champion ? 1 : -1;  // Champions go to end
                            }
                            return (a.name || '').localeCompare(b.name || '');  // Secondary sort by name
                        });

                        self.visibleTrainers = self.trainers.slice();
                        self.visibleVenues = self.venues.slice();
                        self.visibleEvents = self.events.slice();

                        self.displayedCounts = { trainers: 0, venues: 0, events: 0 };
                        self.updateAllCounts();
                        self.renderActiveTabList();
                    }
                },
                error: function() {
                    self.hideLoading();
                }
            });
        },

        /**
         * Create the Google Map instance
         */
        createMap: function() {
            const mapElement = document.getElementById(this.config.mapElementId);

            if (!mapElement) {
                console.error('Map element not found');
                return;
            }

            // Remove loading indicator
            mapElement.innerHTML = '';

            // Create map with options
            // minZoom: 3 prevents tile/marker drift at low zoom levels caused by
            // Google Maps WebGL renderer reading viewport width instead of container width
            // in CSS Grid layouts. Drift is invisible at zoom 4+ but severe at zoom 1-2.
            this.map = new google.maps.Map(mapElement, {
                center: this.config.defaultCenter,
                zoom: this.config.defaultZoom,
                minZoom: 3,
                mapTypeControl: true,
                mapTypeControlOptions: {
                    position: google.maps.ControlPosition.TOP_RIGHT
                },
                streetViewControl: false,
                fullscreenControl: true,
                zoomControl: true,
                zoomControlOptions: {
                    position: google.maps.ControlPosition.RIGHT_CENTER
                },
                styles: this.getMapStyles()
            });

            // Close info window on map click
            this.map.addListener('click', () => {
                this.infoWindow.close();
            });

            // Sync sidebar with map viewport on pan/zoom
            const self = this;
            this.map.addListener('idle', function() {
                self.syncSidebarWithViewport();
            });
        },

        /**
         * Get custom map styles
         */
        getMapStyles: function() {
            return [
                {
                    featureType: 'poi',
                    elementType: 'labels',
                    stylers: [{ visibility: 'off' }]
                },
                {
                    featureType: 'transit',
                    elementType: 'labels',
                    stylers: [{ visibility: 'off' }]
                }
            ];
        },

        /**
         * Load map data via AJAX
         */
        loadMapData: function(filters) {
            const self = this;

            const data = {
                action: 'hvac_get_training_map_data',
                nonce: hvacFindTraining.nonce
            };

            // Add filters if provided
            if (filters) {
                Object.assign(data, filters);
            }

            $.ajax({
                url: hvacFindTraining.ajax_url,
                type: 'POST',
                data: data,
                beforeSend: function() {
                    self.showLoading();
                },
                success: function(response) {
                    if (response.success) {
                        self.trainers = response.data.trainers || [];
                        self.venues = response.data.venues || [];
                        self.events = response.data.events || [];

                        // Sort trainers: non-champions first, champions last, then by name
                        self.trainers.sort(function(a, b) {
                            if (a.is_champion !== b.is_champion) {
                                return a.is_champion ? 1 : -1;  // Champions go to end
                            }
                            return (a.name || '').localeCompare(b.name || '');  // Secondary sort by name
                        });

                        // Initially all items are "visible"
                        self.visibleTrainers = self.trainers.slice();
                        self.visibleVenues = self.venues.slice();
                        self.visibleEvents = self.events.slice();

                        // Reset displayed counts
                        self.displayedCounts = { trainers: 0, venues: 0, events: 0 };

                        self.updateMarkers();
                        self.updateAllCounts();
                        self.renderActiveTabList();
                        // Note: syncSidebarWithViewport will be called by map 'idle' event
                        // to filter items to current viewport
                    } else {
                        self.showMapError(response.data?.message || 'Failed to load data');
                    }
                },
                error: function() {
                    self.showMapError('Network error. Please try again.');
                },
                complete: function() {
                    self.hideLoading();
                }
            });
        },

        /**
         * Update markers on the map
         */
        updateMarkers: function() {
            // Clear existing markers
            this.clearMarkers();

            // Check toggle states
            const showTrainers = $('#hvac-show-trainers').is(':checked');
            const showVenues = $('#hvac-show-venues').is(':checked');
            const showEvents = $('#hvac-show-events').is(':checked');

            // Add trainer markers
            if (showTrainers && this.trainers.length > 0) {
                this.trainers.forEach(trainer => {
                    if (trainer.lat && trainer.lng) {
                        this.addTrainerMarker(trainer);
                    }
                });
            }

            // Add venue markers
            if (showVenues && this.venues.length > 0) {
                this.venues.forEach(venue => {
                    if (venue.lat && venue.lng) {
                        this.addVenueMarker(venue);
                    }
                });
            }

            // Add event markers
            if (showEvents && this.events.length > 0) {
                this.events.forEach(event => {
                    if (event.lat && event.lng) {
                        this.addEventMarker(event);
                    }
                });
            }

            // Initialize clustering
            this.initClustering();

            // Fit bounds if we have markers
            this.fitBounds();

            // Highlight markers for active tab
            this.highlightMarkersForTab(this.activeTab);
        },

        /**
         * Add a trainer marker
         */
        addTrainerMarker: function(trainer) {
            const self = this;

            // Create marker with custom icon (use champion icon for champions)
            const marker = new google.maps.Marker({
                position: { lat: trainer.lat, lng: trainer.lng },
                map: this.map,
                title: trainer.name,
                icon: trainer.is_champion ? this.getChampionIcon() : this.getTrainerIcon(),
                optimized: false  // Required for reliable hover events
            });

            // Store trainer data on marker
            marker.trainerData = trainer;
            marker.markerType = 'trainer';

            // Add hover listener to show info window preview
            marker.addListener('mouseover', function() {
                self.showTrainerInfoWindow(this);
            });

            // Add click listener (also shows info window, for touch devices)
            marker.addListener('click', function() {
                self.showTrainerInfoWindow(this);
            });

            this.trainerMarkers.push(marker);
        },

        /**
         * Add a venue marker
         */
        addVenueMarker: function(venue) {
            const self = this;

            // Create marker with custom icon
            const marker = new google.maps.Marker({
                position: { lat: venue.lat, lng: venue.lng },
                map: this.map,
                title: venue.name,
                icon: this.getVenueIcon(),
                optimized: false  // Required for reliable hover events
            });

            // Store venue data on marker
            marker.venueData = venue;
            marker.markerType = 'venue';

            // Add hover listener to show info window preview
            marker.addListener('mouseover', function() {
                self.showVenueInfoWindow(this);
            });

            // Add click listener (also shows info window, for touch devices)
            marker.addListener('click', function() {
                self.showVenueInfoWindow(this);
            });

            this.venueMarkers.push(marker);
        },

        /**
         * Add an event marker
         */
        addEventMarker: function(event) {
            const self = this;

            // Create marker with custom icon
            const marker = new google.maps.Marker({
                position: { lat: event.lat, lng: event.lng },
                map: this.map,
                title: event.title,
                icon: this.getEventIcon(),
                optimized: false  // Required for reliable hover events
            });

            // Store event data on marker
            marker.eventData = event;
            marker.markerType = 'event';

            // Add hover listener to show info window preview
            marker.addListener('mouseover', function() {
                self.showEventInfoWindow(this);
            });

            // Add click listener (also shows info window, for touch devices)
            marker.addListener('click', function() {
                self.showEventInfoWindow(this);
            });

            this.eventMarkers.push(marker);
        },

        /**
         * Get trainer marker icon
         */
        getTrainerIcon: function() {
            // Use custom icon if available, otherwise use SVG circle
            if (hvacFindTraining.marker_icons?.trainer) {
                return {
                    url: hvacFindTraining.marker_icons.trainer,
                    scaledSize: new google.maps.Size(32, 32)
                };
            }

            // SVG circle marker (light green with dark outline)
            return {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#f0f7e8',
                fillOpacity: 1,
                strokeColor: '#5a8a1a',
                strokeWeight: 2,
                scale: 10
            };
        },

        /**
         * Get champion marker icon (white outline to distinguish from trainers)
         * Champions are measureQuick Certified Champions who don't offer public training
         */
        getChampionIcon: function() {
            // SVG circle marker (light green with white outline)
            return {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#f0f7e8',
                fillOpacity: 1,
                strokeColor: '#ffffff',
                strokeWeight: 2.5,
                scale: 10
            };
        },

        /**
         * Get venue marker icon
         */
        getVenueIcon: function() {
            // Use custom icon if available, otherwise use SVG marker
            if (hvacFindTraining.marker_icons?.venue) {
                return {
                    url: hvacFindTraining.marker_icons.venue,
                    scaledSize: new google.maps.Size(32, 32)
                };
            }

            // SVG marker (green for mQ Approved)
            return {
                path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
                fillColor: '#89c92e',
                fillOpacity: 1,
                strokeColor: '#ffffff',
                strokeWeight: 2,
                scale: 6
            };
        },

        /**
         * Get event marker icon
         */
        getEventIcon: function() {
            // Use custom icon if available, otherwise use SVG circle
            if (hvacFindTraining.marker_icons?.event) {
                return {
                    url: hvacFindTraining.marker_icons.event,
                    scaledSize: new google.maps.Size(32, 32)
                };
            }

            // SVG circle marker (teal for events)
            return {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#0ebaa6',
                fillOpacity: 1,
                strokeColor: '#ffffff',
                strokeWeight: 2,
                scale: 8
            };
        },

        /**
         * Get highlighted trainer marker icon (larger, brighter stroke)
         */
        getTrainerIconHighlighted: function() {
            if (hvacFindTraining.marker_icons?.trainer) {
                return {
                    url: hvacFindTraining.marker_icons.trainer,
                    scaledSize: new google.maps.Size(40, 40),
                    anchor: new google.maps.Point(20, 20)
                };
            }
            return {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#f0f7e8',
                fillOpacity: 1,
                strokeColor: '#3d6e00',
                strokeWeight: 3,
                scale: 14
            };
        },

        /**
         * Get highlighted champion marker icon (larger, brighter stroke)
         */
        getChampionIconHighlighted: function() {
            return {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#f0f7e8',
                fillOpacity: 1,
                strokeColor: '#e0e0e0',
                strokeWeight: 3.5,
                scale: 14
            };
        },

        /**
         * Get highlighted venue marker icon (larger, brighter stroke)
         */
        getVenueIconHighlighted: function() {
            if (hvacFindTraining.marker_icons?.venue) {
                return {
                    url: hvacFindTraining.marker_icons.venue,
                    scaledSize: new google.maps.Size(40, 40),
                    anchor: new google.maps.Point(20, 20)
                };
            }
            return {
                path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
                fillColor: '#89c92e',
                fillOpacity: 1,
                strokeColor: '#e0e0e0',
                strokeWeight: 3,
                scale: 8
            };
        },

        /**
         * Get highlighted event marker icon (larger, brighter stroke)
         */
        getEventIconHighlighted: function() {
            if (hvacFindTraining.marker_icons?.event) {
                return {
                    url: hvacFindTraining.marker_icons.event,
                    scaledSize: new google.maps.Size(40, 40),
                    anchor: new google.maps.Point(20, 20)
                };
            }
            return {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#0ebaa6',
                fillOpacity: 1,
                strokeColor: '#e0e0e0',
                strokeWeight: 3,
                scale: 11
            };
        },

        /**
         * Highlight markers for the active tab category.
         * Active tab markers get larger icons + higher zIndex.
         * Inactive tab markers revert to normal icons + default zIndex.
         */
        highlightMarkersForTab: function(tab) {
            if (!this.map) return;

            const DEFAULT_Z = 1;
            const HIGHLIGHT_Z = 100;

            // Trainer markers
            const trainerHighlighted = (tab === 'trainers');
            this.trainerMarkers.forEach(function(marker) {
                const isChampion = marker.trainerData && marker.trainerData.is_champion;
                if (trainerHighlighted) {
                    marker.setIcon(isChampion ? HVACTrainingMap.getChampionIconHighlighted() : HVACTrainingMap.getTrainerIconHighlighted());
                    marker.setZIndex(HIGHLIGHT_Z);
                } else {
                    marker.setIcon(isChampion ? HVACTrainingMap.getChampionIcon() : HVACTrainingMap.getTrainerIcon());
                    marker.setZIndex(DEFAULT_Z);
                }
            });

            // Venue markers
            const venueHighlighted = (tab === 'venues');
            this.venueMarkers.forEach(function(marker) {
                marker.setIcon(venueHighlighted ? HVACTrainingMap.getVenueIconHighlighted() : HVACTrainingMap.getVenueIcon());
                marker.setZIndex(venueHighlighted ? HIGHLIGHT_Z : DEFAULT_Z);
            });

            // Event markers
            const eventHighlighted = (tab === 'events');
            this.eventMarkers.forEach(function(marker) {
                marker.setIcon(eventHighlighted ? HVACTrainingMap.getEventIconHighlighted() : HVACTrainingMap.getEventIcon());
                marker.setZIndex(eventHighlighted ? HIGHLIGHT_Z : DEFAULT_Z);
            });
        },

        /**
         * Initialize marker clustering
         */
        initClustering: function() {
            // Clear existing clusterer
            if (this.markerClusterer) {
                this.markerClusterer.clearMarkers();
            }

            // Combine all markers
            const allMarkers = [...this.trainerMarkers, ...this.venueMarkers, ...this.eventMarkers];

            if (allMarkers.length === 0) {
                return;
            }

            // Check if MarkerClusterer is available
            if (typeof markerClusterer !== 'undefined' && markerClusterer.MarkerClusterer) {
                this.markerClusterer = new markerClusterer.MarkerClusterer({
                    map: this.map,
                    markers: allMarkers,
                    algorithmOptions: {
                        maxZoom: this.config.clusterZoom
                    }
                });
            }
        },

        /**
         * Clear all markers from the map
         */
        clearMarkers: function() {
            // Clear trainer markers
            this.trainerMarkers.forEach(marker => marker.setMap(null));
            this.trainerMarkers = [];

            // Clear venue markers
            this.venueMarkers.forEach(marker => marker.setMap(null));
            this.venueMarkers = [];

            // Clear event markers
            this.eventMarkers.forEach(marker => marker.setMap(null));
            this.eventMarkers = [];

            // Clear clusterer
            if (this.markerClusterer) {
                this.markerClusterer.clearMarkers();
            }
        },

        /**
         * Fit map bounds to show all markers
         */
        fitBounds: function() {
            const allMarkers = [...this.trainerMarkers, ...this.venueMarkers, ...this.eventMarkers];

            if (allMarkers.length === 0) {
                // Reset to default view
                this.map.setCenter(this.config.defaultCenter);
                this.map.setZoom(this.config.defaultZoom);
                return;
            }

            if (allMarkers.length === 1) {
                // Single marker - center on it
                this.map.setCenter(allMarkers[0].getPosition());
                this.map.setZoom(10);
                return;
            }

            // Calculate bounds
            const bounds = new google.maps.LatLngBounds();
            allMarkers.forEach(marker => {
                bounds.extend(marker.getPosition());
            });

            this.map.fitBounds(bounds, { padding: 50 });
        },

        /**
         * Show trainer info window
         */
        showTrainerInfoWindow: function(marker) {
            const self = this;
            const trainer = marker.trainerData;

            // Create DOM elements safely to avoid XSS
            const container = document.createElement('div');
            container.className = 'hvac-info-window';

            const title = document.createElement('div');
            title.className = 'hvac-info-window-title';
            title.textContent = trainer.name;
            container.appendChild(title);

            // Location: only state for champions, city + state for trainers
            const location = document.createElement('div');
            location.className = 'hvac-info-window-location';
            const locationParts = trainer.is_champion
                ? [trainer.state].filter(Boolean)
                : [trainer.city, trainer.state].filter(Boolean);
            location.textContent = locationParts.join(', ');
            container.appendChild(location);

            if (trainer.certification) {
                const certBadge = document.createElement('span');
                certBadge.className = 'hvac-info-window-cert';
                certBadge.textContent = trainer.certification;
                container.appendChild(certBadge);
            }

            // Only show View Profile button for non-champions (champions don't offer public training)
            if (!trainer.is_champion) {
                const button = document.createElement('button');
                button.className = 'hvac-info-window-btn';
                button.textContent = 'View Profile';
                button.addEventListener('click', function() {
                    self.openTrainerModal(trainer.profile_id);
                });
                container.appendChild(button);
            }

            this.infoWindow.setContent(container);
            this.infoWindow.open(this.map, marker);
        },

        /**
         * Show venue info window
         */
        showVenueInfoWindow: function(marker) {
            const self = this;
            const venue = marker.venueData;

            const eventsText = venue.upcoming_events > 0
                ? venue.upcoming_events + ' upcoming event' + (venue.upcoming_events > 1 ? 's' : '')
                : 'No upcoming events';

            // Create DOM elements safely to avoid XSS
            const container = document.createElement('div');
            container.className = 'hvac-info-window-venue';

            const title = document.createElement('div');
            title.className = 'hvac-info-window-title';
            title.textContent = venue.name;
            container.appendChild(title);

            const address = document.createElement('div');
            address.className = 'hvac-info-window-address';
            address.innerHTML = this.escapeHtml(venue.address || '') + '<br>' +
                               this.escapeHtml(venue.city || '') + ', ' + this.escapeHtml(venue.state || '');
            container.appendChild(address);

            const eventsCount = document.createElement('div');
            eventsCount.className = 'hvac-info-window-events-count';
            eventsCount.textContent = eventsText;
            container.appendChild(eventsCount);

            const button = document.createElement('button');
            button.className = 'hvac-info-window-btn';
            button.textContent = 'View Details';
            button.addEventListener('click', function() {
                self.openVenueModal(venue.id);
            });
            container.appendChild(button);

            this.infoWindow.setContent(container);
            this.infoWindow.open(this.map, marker);
        },

        /**
         * Show event info window
         */
        showEventInfoWindow: function(marker) {
            const event = marker.eventData;

            // Build date/time string
            let dateTimeStr = event.start_date;
            if (event.end_date && event.end_date !== event.start_date) {
                dateTimeStr += ' - ' + event.end_date;
            }
            if (event.is_all_day) {
                dateTimeStr += ' (All Day)';
            } else if (event.start_time) {
                dateTimeStr += ' at ' + event.start_time;
            }

            // Build venue location string
            const venueLocation = [event.venue_city, event.venue_state].filter(Boolean).join(', ');

            // Create DOM elements safely to avoid XSS
            const container = document.createElement('div');
            container.className = 'hvac-info-window-event';

            const title = document.createElement('div');
            title.className = 'hvac-info-window-title';
            title.textContent = event.title;
            container.appendChild(title);

            const dateDiv = document.createElement('div');
            dateDiv.className = 'hvac-info-window-date';
            const calIcon = document.createElement('span');
            calIcon.className = 'dashicons dashicons-calendar-alt';
            dateDiv.appendChild(calIcon);
            dateDiv.appendChild(document.createTextNode(' ' + dateTimeStr));
            container.appendChild(dateDiv);

            if (event.venue_name) {
                const venueDiv = document.createElement('div');
                venueDiv.className = 'hvac-info-window-venue-name';
                venueDiv.textContent = event.venue_name;
                if (venueLocation) {
                    venueDiv.textContent += ' (' + venueLocation + ')';
                }
                container.appendChild(venueDiv);
            }

            // Cost badge
            const costSpan = document.createElement('span');
            costSpan.className = 'hvac-info-window-cost';
            if (event.cost === 'Free' || event.cost.toLowerCase() === 'free') {
                costSpan.classList.add('hvac-free');
            }
            costSpan.textContent = event.cost;
            container.appendChild(costSpan);

            // Past event badge
            if (event.is_past) {
                const pastBadge = document.createElement('span');
                pastBadge.className = 'hvac-info-window-past-badge';
                pastBadge.textContent = 'Past Event';
                container.appendChild(pastBadge);
            }

            // Line break before link
            container.appendChild(document.createElement('br'));
            container.appendChild(document.createElement('br'));

            // View event link (opens in new tab)
            const link = document.createElement('a');
            link.className = 'hvac-info-window-event-link';
            link.href = event.url;
            link.target = '_blank';
            link.rel = 'noopener';
            link.textContent = 'View Event Details';
            container.appendChild(link);

            this.infoWindow.setContent(container);
            this.infoWindow.open(this.map, marker);
        },

        /**
         * Open trainer profile modal
         */
        openTrainerModal: function(profileId) {
            const self = this;
            const $modal = $('#hvac-trainer-modal');
            const $body = $modal.find('.hvac-modal-body');
            const $loading = $modal.find('.hvac-modal-loading');

            // Show modal with loading
            $modal.show();
            $loading.show();
            $body.hide();

            // Close info window
            this.infoWindow.close();

            // Fetch profile data
            $.ajax({
                url: hvacFindTraining.ajax_url,
                type: 'POST',
                data: {
                    action: 'hvac_get_trainer_profile_modal',
                    nonce: hvacFindTraining.nonce,
                    profile_id: profileId
                },
                success: function(response) {
                    if (response.success) {
                        $body.html(response.data.html);
                        $loading.hide();
                        $body.show();
                        // Render reCAPTCHA for dynamically loaded content
                        self.renderRecaptcha($body);
                        self.bindContactForm();
                    } else {
                        $body.html('<p class="hvac-error">Failed to load profile.</p>');
                        $loading.hide();
                        $body.show();
                    }
                },
                error: function() {
                    $body.html('<p class="hvac-error">Network error. Please try again.</p>');
                    $loading.hide();
                    $body.show();
                }
            });
        },

        /**
         * Open venue details modal
         */
        openVenueModal: function(venueId) {
            const self = this;
            const $modal = $('#hvac-venue-modal');

            // Close info window
            this.infoWindow.close();

            // Fetch venue data
            $.ajax({
                url: hvacFindTraining.ajax_url,
                type: 'POST',
                data: {
                    action: 'hvac_get_venue_info',
                    nonce: hvacFindTraining.nonce,
                    venue_id: venueId
                },
                success: function(response) {
                    if (response.success) {
                        const venue = response.data.venue;
                        self.populateVenueModal(venue);
                        $modal.show();
                    }
                }
            });
        },

        /**
         * Populate venue modal with data
         */
        populateVenueModal: function(venue) {
            const self = this;
            const $modal = $('#hvac-venue-modal');

            // Title
            $modal.find('#venue-modal-title').text(venue.name);

            // Address
            const addressParts = [venue.address, venue.city, venue.state, venue.zip].filter(Boolean);
            $modal.find('.hvac-venue-address').text(addressParts.join(', '));

            // Phone
            if (venue.phone) {
                $modal.find('.hvac-venue-phone').html('<strong>Phone:</strong> ' + this.escapeHtml(venue.phone)).show();
            } else {
                $modal.find('.hvac-venue-phone').hide();
            }

            // Capacity
            if (venue.capacity) {
                $modal.find('.hvac-venue-capacity').html('<strong>Capacity:</strong> ' + this.escapeHtml(venue.capacity)).show();
            } else {
                $modal.find('.hvac-venue-capacity').hide();
            }

            // Description
            if (venue.description) {
                $modal.find('.hvac-venue-description').html(venue.description).show();
            } else {
                $modal.find('.hvac-venue-description').hide();
            }

            // Equipment badges
            const $equipmentSection = $modal.find('.hvac-venue-equipment');
            const $equipmentBadges = $modal.find('.hvac-equipment-badges');
            $equipmentBadges.empty();

            if (venue.equipment && venue.equipment.length > 0) {
                venue.equipment.forEach(item => {
                    $equipmentBadges.append(`<span class="hvac-badge hvac-badge-equipment">${this.escapeHtml(item)}</span>`);
                });
                $equipmentSection.show();
            } else {
                $equipmentSection.hide();
            }

            // Amenities badges
            const $amenitiesSection = $modal.find('.hvac-venue-amenities');
            const $amenitiesBadges = $modal.find('.hvac-amenities-badges');
            $amenitiesBadges.empty();

            if (venue.amenities && venue.amenities.length > 0) {
                venue.amenities.forEach(item => {
                    $amenitiesBadges.append(`<span class="hvac-badge hvac-badge-amenity">${this.escapeHtml(item)}</span>`);
                });
                $amenitiesSection.show();
            } else {
                $amenitiesSection.hide();
            }

            // Events list
            const $eventsList = $modal.find('.hvac-venue-events-list');
            const $noEvents = $modal.find('.hvac-venue-no-events');
            $eventsList.empty();

            if (venue.events && venue.events.length > 0) {
                venue.events.forEach(event => {
                    $eventsList.append(`
                        <li>
                            <a href="${this.escapeHtml(event.url)}" target="_blank">${this.escapeHtml(event.title)}</a>
                            <span class="hvac-event-date">${this.escapeHtml(event.date)}</span>
                        </li>
                    `);
                });
                $eventsList.show();
                $noEvents.hide();
            } else {
                $eventsList.hide();
                $noEvents.show();
            }

            // Directions link
            const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${venue.lat},${venue.lng}`;
            $modal.find('.hvac-venue-directions').attr('href', directionsUrl);

            // Set up contact form
            const $form = $modal.find('.hvac-venue-contact-form');
            $form.data('venue-id', venue.id);
            $form.attr('data-venue-id', venue.id);
            $form.show();
            $modal.find('.hvac-form-success').hide();
            $modal.find('.hvac-form-error').hide();
            $form[0].reset();

            // Bind contact form submission
            this.bindVenueContactForm();
        },

        /**
         * Bind venue contact form submission
         */
        bindVenueContactForm: function() {
            const self = this;

            $('.hvac-venue-contact-form').off('submit').on('submit', function(e) {
                e.preventDefault();
                self.submitVenueContactForm($(this));
            });
        },

        /**
         * Submit venue contact form
         */
        submitVenueContactForm: function($form) {
            const self = this;
            const venueId = $form.data('venue-id');
            const $successMsg = $form.siblings('.hvac-form-success');
            const $errorMsg = $form.siblings('.hvac-form-error');
            const $submit = $form.find('button[type="submit"]');

            // Check for reCAPTCHA response
            const recaptchaWidget = $form.find('.g-recaptcha');
            let recaptchaResponse = '';
            if (recaptchaWidget.length && typeof grecaptcha !== 'undefined') {
                // Find the widget ID for this specific form
                const widgetId = recaptchaWidget.data('widget-id');
                if (widgetId !== undefined) {
                    recaptchaResponse = grecaptcha.getResponse(widgetId);
                } else {
                    recaptchaResponse = grecaptcha.getResponse();
                }

                if (!recaptchaResponse) {
                    alert(hvacFindTraining.messages?.captcha_required || 'Please complete the CAPTCHA verification.');
                    return;
                }
            }

            // Collect form data
            const formData = {
                action: 'hvac_submit_venue_contact',
                nonce: hvacFindTraining.nonce,
                venue_id: venueId,
                'g-recaptcha-response': recaptchaResponse
            };

            $form.serializeArray().forEach(field => {
                formData[field.name] = field.value;
            });

            // Submit
            $submit.prop('disabled', true).text('Sending...');
            $successMsg.hide();
            $errorMsg.hide();

            $.ajax({
                url: hvacFindTraining.ajax_url,
                type: 'POST',
                data: formData,
                success: function(response) {
                    if (response.success) {
                        $form.hide();
                        $successMsg.show();
                        // Reset reCAPTCHA for next use
                        self.resetRecaptcha($form);
                    } else {
                        $errorMsg.find('p').text(response.data?.message || 'There was a problem sending your message.');
                        $errorMsg.show();
                        // Reset reCAPTCHA on failure so user can try again
                        self.resetRecaptcha($form);
                    }
                },
                error: function() {
                    $errorMsg.show();
                    self.resetRecaptcha($form);
                },
                complete: function() {
                    $submit.prop('disabled', false).text('Send Message');
                }
            });
        },

        /**
         * Update trainer directory grid
         */
        updateTrainerGrid: function() {
            const $grid = $('#hvac-trainer-grid');
            $grid.empty();

            // Use visible trainers if available (viewport sync), otherwise use all trainers
            const trainersToShow = this.visibleTrainers.length > 0 || this.map
                ? this.visibleTrainers
                : this.trainers;

            if (trainersToShow.length === 0) {
                const message = this.trainers.length > 0
                    ? 'No trainers visible in this area. Zoom out or pan the map to see more.'
                    : 'No trainers found matching your criteria.';
                $grid.html(`<div class="hvac-empty-state"><span class="dashicons dashicons-businessperson"></span><p>${message}</p></div>`);
                $('.hvac-load-more-wrapper').hide();
                return;
            }

            // Display trainers (show first batch for compact sidebar, load more on request)
            const displayCount = Math.min(trainersToShow.length, this.displayedCounts.trainers + this.itemsPerPage);
            this.displayedCounts.trainers = displayCount;

            for (let i = 0; i < displayCount; i++) {
                $grid.append(this.createTrainerCard(trainersToShow[i]));
            }

            // Show load more if there are more trainers
            if (trainersToShow.length > displayCount) {
                $('.hvac-load-more-wrapper').show();
            } else {
                $('.hvac-load-more-wrapper').hide();
            }
        },

        /**
         * Create trainer card HTML
         */
        createTrainerCard: function(trainer) {
            const imageHtml = trainer.image
                ? `<img src="${this.escapeHtml(trainer.image)}" alt="${this.escapeHtml(trainer.name)}">`
                : '<div class="hvac-trainer-card-avatar"><span class="dashicons dashicons-businessperson"></span></div>';

            const certHtml = trainer.certifications && trainer.certifications.length > 0
                ? trainer.certifications.map(cert => `<span class="hvac-cert-badge">${this.escapeHtml(cert)}</span>`).join('')
                : '';

            // Location: only state for champions, city + state for trainers
            const locationHtml = trainer.is_champion
                ? this.escapeHtml(trainer.state)
                : `${this.escapeHtml(trainer.city)}, ${this.escapeHtml(trainer.state)}`;

            // CSS class: non-clickable for champions (no contact form/modal)
            const cardClass = trainer.is_champion
                ? 'hvac-trainer-card hvac-champion-card'
                : 'hvac-trainer-card';

            // Champions don't have clickable profile_id (prevents modal)
            const profileIdAttr = trainer.is_champion ? '' : trainer.profile_id;

            return `
                <div class="${cardClass}" data-profile-id="${profileIdAttr}">
                    <div class="hvac-trainer-card-image">${imageHtml}</div>
                    <div class="hvac-trainer-card-info">
                        <div class="hvac-trainer-card-name">${this.escapeHtml(trainer.name)}</div>
                        <div class="hvac-trainer-card-location">${locationHtml}</div>
                        <div class="hvac-trainer-card-certs">${certHtml}</div>
                    </div>
                </div>
            `;
        },

        /**
         * Update counts display (legacy method - now uses updateAllCounts)
         * @param {number} visible - Number of visible trainers (or total if no viewport filtering)
         * @param {number} total - Total number of trainers (optional, for "X of Y" format)
         */
        updateCounts: function(visible, total) {
            // Update all tab counts
            this.updateAllCounts();
        },

        /**
         * Bind event handlers
         */
        bindEvents: function() {
            const self = this;

            // Trainer card click
            $(document).on('click', '.hvac-trainer-card', function() {
                const profileId = $(this).data('profile-id');
                if (profileId) {
                    self.openTrainerModal(profileId);
                }
            });

            // Venue card click
            $(document).on('click', '.hvac-venue-card', function() {
                const venueId = $(this).data('venue-id');
                if (venueId) {
                    self.openVenueModal(venueId);
                }
            });

            // Event card click - open in new tab
            $(document).on('click', '.hvac-event-card', function() {
                const eventUrl = $(this).data('event-url');
                if (eventUrl) {
                    window.open(eventUrl, '_blank', 'noopener');
                }
            });

            // Modal close
            $(document).on('click', '.hvac-modal-close, .hvac-modal-overlay', function() {
                $('.hvac-training-modal').hide();
            });

            // ESC key to close modal
            $(document).on('keydown', function(e) {
                if (e.key === 'Escape') {
                    $('.hvac-training-modal').hide();
                }
            });

            // Marker toggles
            $('#hvac-show-trainers, #hvac-show-venues, #hvac-show-events').on('change', function() {
                self.updateMarkers();
            });

            // Load more button
            $('#hvac-load-more').on('click', function() {
                self.loadMoreTrainers();
            });

            // Reset map view button
            $('#hvac-reset-map').on('click', function() {
                self.resetMapView();
            });
        },

        /**
         * Bind contact form in modal
         */
        bindContactForm: function() {
            const self = this;

            $('.hvac-training-contact-form').off('submit').on('submit', function(e) {
                e.preventDefault();
                self.submitContactForm($(this));
            });
        },

        /**
         * Submit contact form
         */
        submitContactForm: function($form) {
            const self = this;
            const trainerId = $form.data('trainer-id');
            const profileId = $form.data('profile-id');
            const $successMsg = $form.siblings('.hvac-form-success');
            const $errorMsg = $form.siblings('.hvac-form-error');
            const $submit = $form.find('button[type="submit"]');

            // Check for reCAPTCHA response
            const recaptchaWidget = $form.find('.g-recaptcha');
            let recaptchaResponse = '';
            if (recaptchaWidget.length && typeof grecaptcha !== 'undefined') {
                // Find the widget ID for this specific form
                const widgetId = recaptchaWidget.data('widget-id');
                if (widgetId !== undefined) {
                    recaptchaResponse = grecaptcha.getResponse(widgetId);
                } else {
                    recaptchaResponse = grecaptcha.getResponse();
                }

                if (!recaptchaResponse) {
                    alert(hvacFindTraining.messages?.captcha_required || 'Please complete the CAPTCHA verification.');
                    return;
                }
            }

            // Collect form data
            const formData = {
                action: 'hvac_submit_contact_form',
                nonce: hvacFindTraining.nonce,
                trainer_id: trainerId,
                trainer_profile_id: profileId,
                'g-recaptcha-response': recaptchaResponse
            };

            $form.serializeArray().forEach(field => {
                formData[field.name] = field.value;
            });

            // Submit
            $submit.prop('disabled', true).text('Sending...');
            $successMsg.hide();
            $errorMsg.hide();

            $.ajax({
                url: hvacFindTraining.ajax_url,
                type: 'POST',
                data: formData,
                success: function(response) {
                    if (response.success) {
                        $form.hide();
                        $successMsg.show();
                        // Reset reCAPTCHA for next use
                        self.resetRecaptcha($form);
                    } else {
                        $errorMsg.find('p').text(response.data?.message || 'There was an error sending your message.');
                        $errorMsg.show();
                        // Reset reCAPTCHA on failure so user can try again
                        self.resetRecaptcha($form);
                    }
                },
                error: function() {
                    $errorMsg.show();
                    self.resetRecaptcha($form);
                },
                complete: function() {
                    $submit.prop('disabled', false).text('Send Message');
                }
            });
        },

        /**
         * Load more items for the active tab
         */
        loadMoreTrainers: function() {
            switch (this.activeTab) {
                case 'trainers':
                    this.loadMoreForTab('trainers', this.visibleTrainers.length > 0 ? this.visibleTrainers : this.trainers, '#hvac-trainer-grid', '.hvac-trainer-card');
                    break;
                case 'venues':
                    this.loadMoreForTab('venues', this.visibleVenues.length > 0 ? this.visibleVenues : this.venues, '#hvac-venue-grid', '.hvac-venue-card');
                    break;
                case 'events':
                    this.loadMoreForTab('events', this.visibleEvents.length > 0 ? this.visibleEvents : this.events, '#hvac-event-grid', '.hvac-event-card');
                    break;
            }
        },

        /**
         * Load more items for a specific tab
         */
        loadMoreForTab: function(tabType, items, gridSelector, cardSelector) {
            const $grid = $(gridSelector);
            const currentCount = $grid.find(cardSelector).length;

            for (let i = currentCount; i < currentCount + this.itemsPerPage && i < items.length; i++) {
                switch (tabType) {
                    case 'trainers':
                        $grid.append(this.createTrainerCard(items[i]));
                        break;
                    case 'venues':
                        $grid.append(this.createVenueCard(items[i]));
                        break;
                    case 'events':
                        $grid.append(this.createEventCard(items[i]));
                        break;
                }
            }

            this.displayedCounts[tabType] = $grid.find(cardSelector).length;

            if ($grid.find(cardSelector).length >= items.length) {
                $('.hvac-load-more-wrapper').hide();
            }
        },

        /**
         * Handle window resize for map
         */
        handleWindowResize: function() {
            const self = this;
            let resizeTimer;

            window.addEventListener('resize', function() {
                clearTimeout(resizeTimer);
                resizeTimer = setTimeout(function() {
                    if (self.map) {
                        google.maps.event.trigger(self.map, 'resize');
                    }
                }, 250);
            });
        },

        /**
         * Initialize sidebar toggle for mobile
         */
        initSidebarToggle: function() {
            const self = this;

            $(document).on('click', '.hvac-sidebar-toggle', function() {
                const $sidebar = $('.hvac-sidebar');
                const $toggle = $(this);
                const isCollapsed = $sidebar.hasClass('collapsed');

                $sidebar.toggleClass('collapsed');

                // Update ARIA attributes
                $toggle.attr('aria-expanded', isCollapsed ? 'true' : 'false');

                // Trigger map resize after sidebar animation
                setTimeout(function() {
                    if (self.map) {
                        google.maps.event.trigger(self.map, 'resize');
                    }
                }, 300);
            });
        },

        /**
         * Get user's location
         */
        getUserLocation: function(callback) {
            if (!navigator.geolocation) {
                callback(null, hvacFindTraining.messages.geolocation_unsupported);
                return;
            }

            navigator.geolocation.getCurrentPosition(
                function(position) {
                    callback({
                        lat: position.coords.latitude,
                        lng: position.coords.longitude
                    });
                },
                function(error) {
                    callback(null, hvacFindTraining.messages.geolocation_error);
                }
            );
        },

        /**
         * Center map on location
         */
        centerOnLocation: function(lat, lng, zoom) {
            this.map.setCenter({ lat: lat, lng: lng });
            this.map.setZoom(zoom || 10);
        },

        /**
         * Reset map to fit all markers (or default view if none)
         */
        resetMapView: function() {
            if (!this.map) return;
            this.fitBounds();
        },

        /**
         * Sync sidebar lists with visible map viewport
         */
        syncSidebarWithViewport: function() {
            if (!this.map) {
                return;
            }

            // Get current map bounds
            const bounds = this.map.getBounds();
            if (!bounds) {
                return;
            }

            // Filter trainers to those visible in current viewport
            this.visibleTrainers = this.trainers.filter(trainer => {
                if (!trainer.lat || !trainer.lng) {
                    return false;
                }
                const position = new google.maps.LatLng(trainer.lat, trainer.lng);
                return bounds.contains(position);
            });

            // Filter venues to those visible in current viewport
            this.visibleVenues = this.venues.filter(venue => {
                if (!venue.lat || !venue.lng) {
                    return false;
                }
                const position = new google.maps.LatLng(venue.lat, venue.lng);
                return bounds.contains(position);
            });

            // Filter events to those visible in current viewport
            this.visibleEvents = this.events.filter(event => {
                if (!event.lat || !event.lng) {
                    return false;
                }
                const position = new google.maps.LatLng(event.lat, event.lng);
                return bounds.contains(position);
            });

            // Reset displayed counts when viewport changes
            this.displayedCounts = { trainers: 0, venues: 0, events: 0 };

            // Update all counts
            this.updateAllCounts();

            // Render the active tab's list
            this.renderActiveTabList();
        },

        /**
         * Show loading state
         */
        showLoading: function() {
            const gridId = this.activeTab === 'events' ? '#hvac-event-grid' : this.activeTab === 'venues' ? '#hvac-venue-grid' : '#hvac-trainer-grid';
            const label = this.activeTab === 'events' ? 'events' : this.activeTab === 'venues' ? 'venues' : 'trainers';
            $(gridId).html('<div class="hvac-grid-loading"><span class="dashicons dashicons-update-alt hvac-spin"></span> Loading ' + label + '...</div>');
        },

        /**
         * Hide loading state
         */
        hideLoading: function() {
            $('.hvac-grid-loading').remove();
        },

        /**
         * Show map error
         */
        showMapError: function(message) {
            const $map = $('#' + this.config.mapElementId);
            $map.html(`
                <div class="hvac-map-loading">
                    <span class="dashicons dashicons-warning"></span>
                    <p>${this.escapeHtml(message)}</p>
                </div>
            `);
        },

        /**
         * Initialize tab navigation
         */
        initTabs: function() {
            const self = this;

            // Tab click handlers
            $(document).on('click', '.hvac-tab', function() {
                const tab = $(this).data('tab');
                self.switchTab(tab);
            });

            // Keyboard navigation for tabs
            $(document).on('keydown', '.hvac-tab', function(e) {
                const $tabs = $('.hvac-tab');
                const currentIndex = $tabs.index(this);
                let newIndex = currentIndex;

                if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
                    newIndex = currentIndex > 0 ? currentIndex - 1 : $tabs.length - 1;
                    e.preventDefault();
                } else if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
                    newIndex = currentIndex < $tabs.length - 1 ? currentIndex + 1 : 0;
                    e.preventDefault();
                } else if (e.key === 'Home') {
                    newIndex = 0;
                    e.preventDefault();
                } else if (e.key === 'End') {
                    newIndex = $tabs.length - 1;
                    e.preventDefault();
                }

                if (newIndex !== currentIndex) {
                    $tabs.eq(newIndex).focus().click();
                }
            });

            // Info button handler
            $(document).on('click', '#hvac-info-btn', function() {
                $('#hvac-info-modal').show();
            });

            // Info modal close
            $('#hvac-info-modal').on('click', '.hvac-modal-close, .hvac-modal-overlay', function() {
                $('#hvac-info-modal').hide();
            });
        },

        /**
         * Switch to a different tab
         */
        switchTab: function(tab) {
            if (tab === this.activeTab) return;

            this.activeTab = tab;

            // Update tab buttons
            $('.hvac-tab').removeClass('active').attr('aria-selected', 'false');
            $(`.hvac-tab[data-tab="${tab}"]`).addClass('active').attr('aria-selected', 'true');

            // Update panels
            $('.hvac-tab-panel').removeClass('active').attr('hidden', '');
            $(`#hvac-panel-${tab}`).addClass('active').removeAttr('hidden');

            // Update search placeholder
            this.updateSearchPlaceholder(tab);

            // Highlight markers for active tab
            this.highlightMarkersForTab(tab);

            // Reset displayed count for current tab
            this.displayedCounts[tab] = 0;

            // Render active tab list
            this.renderActiveTabList();
        },

        /**
         * Update search placeholder based on active tab
         */
        updateSearchPlaceholder: function(tab) {
            const placeholders = {
                trainers: 'Search trainers...',
                venues: 'Search venues...',
                events: 'Search events...'
            };
            $('#hvac-training-search').attr('placeholder', placeholders[tab] || 'Search...');
        },

        /**
         * Render the active tab's list
         */
        renderActiveTabList: function() {
            switch (this.activeTab) {
                case 'trainers':
                    this.updateTrainerGrid();
                    break;
                case 'venues':
                    this.updateVenueGrid();
                    break;
                case 'events':
                    this.updateEventGrid();
                    break;
            }
        },

        /**
         * Update venue grid
         */
        updateVenueGrid: function() {
            const $grid = $('#hvac-venue-grid');
            $grid.empty();

            const venuesToShow = this.visibleVenues.length > 0 || this.map
                ? this.visibleVenues
                : this.venues;

            if (venuesToShow.length === 0) {
                const message = this.venues.length > 0
                    ? 'No venues visible in this area. Zoom out or pan the map to see more.'
                    : 'No venues found matching your criteria.';
                $grid.html(`<div class="hvac-empty-state"><span class="dashicons dashicons-building"></span><p>${message}</p></div>`);
                $('.hvac-load-more-wrapper').hide();
                return;
            }

            const displayCount = Math.min(venuesToShow.length, this.displayedCounts.venues + this.itemsPerPage);
            this.displayedCounts.venues = displayCount;

            for (let i = 0; i < displayCount; i++) {
                $grid.append(this.createVenueCard(venuesToShow[i]));
            }

            if (venuesToShow.length > displayCount) {
                $('.hvac-load-more-wrapper').show();
            } else {
                $('.hvac-load-more-wrapper').hide();
            }
        },

        /**
         * Create venue card HTML
         */
        createVenueCard: function(venue) {
            const location = [venue.city, venue.state].filter(Boolean).join(', ');
            const eventsText = venue.upcoming_events > 0
                ? `${venue.upcoming_events} upcoming event${venue.upcoming_events > 1 ? 's' : ''}`
                : 'No upcoming events';

            return `
                <div class="hvac-venue-card" data-venue-id="${venue.id}">
                    <div class="hvac-venue-card-icon">
                        <span class="dashicons dashicons-building"></span>
                    </div>
                    <div class="hvac-venue-card-info">
                        <div class="hvac-venue-card-name">${this.escapeHtml(venue.name)}</div>
                        <div class="hvac-venue-card-location">${this.escapeHtml(location)}</div>
                        <div class="hvac-venue-card-events">${eventsText}</div>
                    </div>
                </div>
            `;
        },

        /**
         * Update event grid
         */
        updateEventGrid: function() {
            const $grid = $('#hvac-event-grid');
            $grid.empty();

            const eventsToShow = this.visibleEvents.length > 0 || this.map
                ? this.visibleEvents
                : this.events;

            if (eventsToShow.length === 0) {
                const message = this.events.length > 0
                    ? 'No events visible in this area. Zoom out or pan the map to see more.'
                    : 'No events found matching your criteria.';
                $grid.html(`<div class="hvac-empty-state"><span class="dashicons dashicons-calendar-alt"></span><p>${message}</p></div>`);
                $('.hvac-load-more-wrapper').hide();
                return;
            }

            const displayCount = Math.min(eventsToShow.length, this.displayedCounts.events + this.itemsPerPage);
            this.displayedCounts.events = displayCount;

            for (let i = 0; i < displayCount; i++) {
                $grid.append(this.createEventCard(eventsToShow[i]));
            }

            if (eventsToShow.length > displayCount) {
                $('.hvac-load-more-wrapper').show();
            } else {
                $('.hvac-load-more-wrapper').hide();
            }
        },

        /**
         * Create event card HTML
         */
        createEventCard: function(event) {
            // Parse date for month/day display
            const dateObj = new Date(event.start_date);
            const month = dateObj.toLocaleString('en-US', { month: 'short' }).toUpperCase();
            const day = dateObj.getDate();

            const venueText = event.venue_name || '';
            const costClass = (event.cost === 'Free' || event.cost.toLowerCase() === 'free') ? 'hvac-free' : '';
            const pastClass = event.is_past ? 'hvac-event-past' : '';
            const pastBadge = event.is_past ? '<span class="hvac-event-card-past-badge">Past</span>' : '';

            return `
                <div class="hvac-event-card ${pastClass}" data-event-url="${this.escapeHtml(event.url)}">
                    <div class="hvac-event-card-date">
                        <span class="hvac-event-card-month">${month}</span>
                        <span class="hvac-event-card-day">${day}</span>
                    </div>
                    <div class="hvac-event-card-info">
                        <div class="hvac-event-card-title">${this.escapeHtml(event.title)}</div>
                        <div class="hvac-event-card-venue">${venueText ? 'at ' + this.escapeHtml(venueText) : ''}</div>
                        <div class="hvac-event-card-meta">
                            <span class="hvac-event-card-cost ${costClass}">${this.escapeHtml(event.cost)}</span>
                            ${pastBadge}
                        </div>
                    </div>
                </div>
            `;
        },

        /**
         * Update all tab counts
         */
        updateAllCounts: function() {
            const trainerCount = this.visibleTrainers.length || this.trainers.length;
            const venueCount = this.visibleVenues.length || this.venues.length;
            const eventCount = this.visibleEvents.length || this.events.length;

            $('[data-count="trainers"]').text(trainerCount);
            $('[data-count="venues"]').text(venueCount);
            $('[data-count="events"]').text(eventCount);
        },

        /**
         * Escape HTML for safe output
         */
        escapeHtml: function(text) {
            if (!text) return '';
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        },

        /**
         * Render reCAPTCHA widget for dynamically loaded content
         * Google's auto-render only works for elements present at page load,
         * so we need to explicitly render widgets added via AJAX.
         *
         * @param {jQuery} $container The container with .g-recaptcha elements
         */
        renderRecaptcha: function($container) {
            if (typeof grecaptcha === 'undefined' || typeof grecaptcha.render !== 'function') {
                return;
            }

            const siteKey = hvacFindTraining.recaptcha_site_key;
            if (!siteKey) {
                return;
            }

            $container.find('.g-recaptcha').each(function() {
                const $widget = $(this);
                // Only render if not already rendered (no iframe inside)
                if ($widget.find('iframe').length === 0) {
                    try {
                        const widgetId = grecaptcha.render(this, {
                            sitekey: siteKey
                        });
                        // Store widget ID for later reset operations
                        $widget.data('widget-id', widgetId);
                    } catch (e) {
                        // Widget may already be rendered, ignore
                        console.log('reCAPTCHA render skipped:', e.message);
                    }
                }
            });
        },

        /**
         * Reset reCAPTCHA widget after form submission
         *
         * @param {jQuery} $form The form containing the reCAPTCHA widget
         */
        resetRecaptcha: function($form) {
            if (typeof grecaptcha === 'undefined') {
                return;
            }

            const recaptchaWidget = $form.find('.g-recaptcha');
            if (recaptchaWidget.length) {
                const widgetId = recaptchaWidget.data('widget-id');
                if (widgetId !== undefined) {
                    grecaptcha.reset(widgetId);
                } else {
                    grecaptcha.reset();
                }
            }
        }
    };

    // Initialize when document is ready
    $(document).ready(function() {
        // Wait a moment for Google Maps to fully load
        if ($('#hvac-training-map').length) {
            setTimeout(function() {
                HVACTrainingMap.init();
            }, 100);
        }
    });

})(jQuery);
