/**
 * Havenlytics Property Map JavaScript 
 *
 * @package Havenlytics
 * @version 2.2.1
 */
(function($) {
    'use strict';
    
    class HavenlyticsPropertyMap {
        constructor() {
            this.map = null;
            this.markers = [];
            this.isMapInitialized = false;
            this.isLoading = false;
            this.clusterGroups = [];
            this.currentPage = 1;
            this.maxPages = 1;
            this.allMapProperties = [];
            this.propertiesPerPage = parseInt(window.hvnly_PROPERTY_ajax?.properties_per_page) || 
                                    parseInt(window.hvnly_PROPERTY_ajax?.per_page) || 12;
            this.propertiesByPage = {};
            this.maxLoadedPage = 0;
            this.refreshTimer = null;
            this.nonce = window.hvnly_PROPERTY_ajax?.nonce || '';
            this.ajaxUrl = window.hvnly_PROPERTY_ajax?.ajax_url || window.ajaxurl;
            this.debugMode = false;
            
            this.mapConfig = window.hvnly_map_params || {};
            
            this.mapProvider = this.mapConfig.provider || 'leaflet';
            this.apiKey = this.mapConfig.api_key || '';
            
            if (this.mapProvider === 'google' && this.apiKey && this.apiKey !== '') {
                this.mapProvider = 'google';
            } else if (this.mapProvider === 'google' && (!this.apiKey || this.apiKey === '')) {
                this.mapProvider = 'leaflet';
            }
            
            this.init();
        }
        
        init() {
            this.initializeComponents();
            this.bindEvents();
        }
        
        initializeComponents() {
            this.initMapView();
        }
        
        bindEvents() {
            this.bindMapPaginationEvents();
            this.bindFilterEvents();
        }
        
        bindMapPaginationEvents() {
            const self = this;
            
            $(document).on('click', '#hvnlyLoadMorePropertyBtn', function(e) {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    self.currentPage++;
                    self.loadMoreMapProperties();
                    return false;
                }
            });
            
            $(document).on('click', '.hvnly-property-pagination-item', function(e) {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    
                    if ($(this).hasClass('active') || $(this).hasClass('dots')) return;
                    
                    const page = $(this).data('page');
                    if (page) {
                        self.loadCumulativeToPage(parseInt(page));
                    }
                    
                    return false;
                }
            });
        }
        
        bindFilterEvents() {
            const self = this;
            
            $(document).on('change', '.hvnly-property-sort-select', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    self.refreshMapWithCurrentFilters();
                }
            });
            
            $(document).on('change', '#hvnly-filter-sidebar input[name="property_ids[]"], #hvnly-filter-sidebar input[name="hvnly_prop_badges[]"]', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    setTimeout(() => self.refreshMapWithCurrentFilters(), 100);
                }
            });
            
            $(document).on('change', '#hvnly-filter-sidebar select', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    setTimeout(() => self.refreshMapWithCurrentFilters(), 100);
                }
            });
            
            $(document).on('change', '#hvnly-filter-sidebar input[type="checkbox"], #hvnly-filter-sidebar select', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    setTimeout(() => self.refreshMapWithCurrentFilters(), 100);
                }
            });
            
            $(document).on('change', '.hvnly-property-tax-multichebox input', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    setTimeout(() => self.refreshMapWithCurrentFilters(), 100);
                }
            });
            
            $(document).on('input', '.hvnly-ajax-search input[name="address_keyword"]', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    setTimeout(() => self.refreshMapWithCurrentFilters(), 300);
                }
            });
            
            $(document).on('submit', '#hvnly-property-search-form__box', function(e) {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    e.preventDefault();
                    self.currentPage = 1;
                    self.refreshMapWithCurrentFilters();
                }
            });
            
            $(document).on('change', '#hvnly-property-search-bedrooms, #hvnly-property-search-bathrooms, #hvnly-property-search-min-price, #hvnly-property-search-max-price', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    self.currentPage = 1;
                    self.refreshMapWithCurrentFilters();
                }
            });
            
            $(document).on('click', '.hvnly-property-reset-filters-btn', function() {
                if ($('.hvnly-property-view-btn.active[data-view="map"]').length) {
                    if (self.refreshTimer) {
                        clearTimeout(self.refreshTimer);
                    }
                    
                    self.refreshTimer = setTimeout(() => {
                        self.currentPage = 1;
                        self.refreshMapWithCurrentFilters();
                    }, 500);
                }
            });
        }
        
        refreshMapWithCurrentFilters() {
            this.propertiesByPage = {};
            this.maxLoadedPage = 0;
            
            if (this.refreshTimer) {
                clearTimeout(this.refreshTimer);
            }
            
            this.refreshTimer = setTimeout(() => {
                this.clearMap();
                this.fetchPropertiesForMap();
            }, 300);
        }
        
        clearMap() {
            if (this.map) {
                if (this.mapProvider === 'google') {
                    if (this.markers && this.markers.length) {
                        this.markers.forEach(marker => {
                            if (marker && typeof marker.setMap === 'function') {
                                marker.setMap(null);
                            }
                        });
                    }
                } else {
                    if (this.markers && this.markers.length) {
                        this.markers.forEach(marker => {
                            if (marker && typeof this.map.removeLayer === 'function') {
                                try {
                                    this.map.removeLayer(marker);
                                } catch(e) {}
                            }
                        });
                    }
                    
                    if (this.clusterGroups && this.clusterGroups.length) {
                        this.clusterGroups.forEach(group => {
                            if (group && typeof this.map.removeLayer === 'function') {
                                try {
                                    this.map.removeLayer(group);
                                } catch(e) {}
                            }
                        });
                    }
                }
                
                this.markers = [];
                this.clusterGroups = [];
                this.allMapProperties = [];
            }
        }
        
        fetchSinglePage(page) {
            return new Promise((resolve, reject) => {
                const formData = new FormData();
                formData.append('action', 'hvnly_get_properties_for_map');
                formData.append('nonce', this.nonce);
                formData.append('page', page);
                formData.append('per_page', this.propertiesPerPage);
                
                const currentFilters = window.havenlyticsAJAX?.getFormData ? window.havenlyticsAJAX.getFormData() : null;
                if (currentFilters) {
                    for (let key in currentFilters) {
                        if (key !== 'action' && key !== 'nonce' && key !== 'page' && key !== 'per_page') {
                            if (Array.isArray(currentFilters[key])) {
                                currentFilters[key].forEach(value => {
                                    formData.append(key + '[]', value);
                                });
                            } else {
                                formData.append(key, currentFilters[key]);
                            }
                        }
                    }
                } else {
                    this.collectAllFilterValues(formData);
                }
                
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 10000);
                
                fetch(this.ajaxUrl, {
                    method: 'POST',
                    body: formData,
                    signal: controller.signal
                })
                .then(response => {
                    clearTimeout(timeoutId);
                    if (!response.ok) {
                        return response.text().then(text => {
                            throw new Error(`HTTP error! status: ${response.status}, message: ${text}`);
                        });
                    }
                    return response.json();
                })
                .then(data => {
                    resolve(data);
                })
                .catch(error => {
                    clearTimeout(timeoutId);
                    reject(error);
                });
            });
        }
        
        async loadCumulativeToPage(targetPage) {
            if (targetPage < 1 || this.isLoading) return;
            
            this.isLoading = true;
            
            const mapLoading = document.querySelector('.hvnly-map-loading');
            if (mapLoading) {
                mapLoading.style.display = 'flex';
            }
            
            try {
                this.clearMap();
                
                let allProperties = [];
                
                for (let page = 1; page <= targetPage; page++) {
                    if (this.propertiesByPage[page]) {
                        allProperties = allProperties.concat(this.propertiesByPage[page]);
                    } else {
                        const data = await this.fetchSinglePage(page);
                        if (data && data.success && data.data.properties) {
                            this.propertiesByPage[page] = data.data.properties;
                            allProperties = allProperties.concat(data.data.properties);
                        }
                    }
                }
                
                if (allProperties.length > 0) {
                    if (!this.isMapInitialized || !this.map) {
                        this.initializePropertiesMap(allProperties);
                    } else {
                        this.addPropertiesToMap(allProperties);
                    }
                }
                
                this.currentPage = targetPage;
                this.maxLoadedPage = Math.max(this.maxLoadedPage, targetPage);
                
                const uiData = await this.fetchSinglePage(targetPage);
                if (uiData && uiData.success) {
                    this.updateMainPaginationDisplay(uiData.data);
                }
            } catch (error) {
                if (error.name === 'AbortError') {
                    this.showMapError('Request timed out. Please try again.');
                } else {
                    this.showMapError('Error loading properties: ' + error.message);
                }
            } finally {
                if (mapLoading) {
                    mapLoading.style.display = 'none';
                }
                this.isLoading = false;
            }
        }
        
        initMapView() {
            const self = this;
            let mapViewInitialized = false;
        
            $(document).on('click', '.hvnly-property-view-btn[data-view="map"]', function(e) {
                e.preventDefault();
                
                if (self.isLoading) {
                    return;
                }
            
                $('.hvnly-property-view-btn').removeClass('active');
                $(this).addClass('active');
            
                $('#view-type-input').val('map');
            
                if (window.havenlyticsAJAX && typeof window.havenlyticsAJAX.updateBrowserUrl === 'function') {
                    window.havenlyticsAJAX.updateBrowserUrl();
                } else {
                    self.updateBrowserUrlFallback();
                }
            
                self.isMapInitialized = false;
                self.currentPage = 1;
                self.propertiesByPage = {};
                self.maxLoadedPage = 0;
                
                self.removeExistingMapView();
            
                setTimeout(() => {
                    self.loadPropertyMap();
                }, 100);
            });
        
            const activeViewBtn = document.querySelector('.hvnly-property-view-btn.active[data-view="map"]');
            if (activeViewBtn && !mapViewInitialized) {
                mapViewInitialized = true;
                setTimeout(() => {
                    self.loadPropertyMap();
                }, 500);
            }
        }
        
        updateBrowserUrlFallback() {
            const url = new URL(window.location);
            url.searchParams.set('view_type', 'map');
            window.history.pushState({}, '', url);
        }
        
        loadPropertyMap() {
            const self = this;
        
            if (this.isLoading) {
                return;
            }
        
            this.isLoading = true;
        
            const propertyGrid = document.querySelector('.hvnly-property-grid-view');
            const mapPlaceholder = document.getElementById('hvnly-map-placeholder');
        
            if (!propertyGrid || !mapPlaceholder) {
                this.isLoading = false;
                return;
            }
        
            propertyGrid.style.display = 'none';
            mapPlaceholder.style.display = 'block';
            
            if (mapPlaceholder.querySelector('.hvnly-map-view')) {
                this.isLoading = false;
                if (this.map && typeof this.map.invalidateSize === 'function') {
                    setTimeout(() => this.map.invalidateSize(), 100);
                }
                this.fetchPropertiesForMap();
                return;
            }
        
            mapPlaceholder.innerHTML = '';
        
            $.ajax({
                url: this.ajaxUrl,
                type: 'POST',
                data: {
                    action: 'hvnly_render_map_container',
                    nonce: this.nonce,
                    provider: this.mapProvider
                },
                success: function(response) {
                    if (response.success && response.data.html) {
                        mapPlaceholder.innerHTML = response.data.html;
                        self.attachMapEvents();
                        setTimeout(() => {
                            self.fetchPropertiesForMap();
                        }, 150);
                    } else {
                        self.createFallbackMapContainer(mapPlaceholder);
                        self.fetchPropertiesForMap();
                    }
                    self.isLoading = false;
                },
                error: function() {
                    self.createFallbackMapContainer(mapPlaceholder);
                    self.fetchPropertiesForMap();
                    self.isLoading = false;
                }
            });
        }
        
        attachMapEvents() {
            const self = this;
            const fullscreenBtn = document.querySelector('.hvnly-map-fullscreen-btn');
            if (fullscreenBtn) {
                const newBtn = fullscreenBtn.cloneNode(true);
                fullscreenBtn.parentNode.replaceChild(newBtn, fullscreenBtn);
                newBtn.addEventListener('click', function(e) {
                    e.preventDefault();
                    self.toggleFullscreen();
                });
            }
        }
        
        createFallbackMapContainer(container) {
            if (!container) {
                container = document.getElementById('hvnly-map-placeholder');
            }
            if (!container) return;
            
            const showFullscreen = this.mapConfig.show_fullscreen !== false;
            const showZoomControl = this.mapConfig.show_zoom_control !== false;
            const showScrollWheel = this.mapConfig.show_scroll_wheel !== false;
            const mapZoom = this.mapConfig.zoom_level || 12;
            
            let mapHtml = '';
            
            if (this.mapProvider === 'google') {
                mapHtml = `
                    <div class="hvnly-map-view hvnly-google-map" id="hvnly-map-view-google" data-provider="google" data-zoom="${mapZoom}" data-scroll-wheel="${showScrollWheel}" style="height: 550px; min-height: 550px;">
                        <div class="hvnly-map-container" style="height: 100%;">
                            <div id="hvnly-properties-map" class="hvnly-properties-map" data-zoom-control="${showZoomControl}" style="height: 100%; width: 100%;"></div>
                            ${showFullscreen ? `<button id="hvnly-google-map-fullscreen-btn" class="hvnly-map-fullscreen-btn hvnly-google-map-fullscreen-btn" title="Toggle Fullscreen" data-fullscreen-target="hvnly-properties-map"><i class="fas fa-expand"></i></button>` : ''}
                            <div class="hvnly-map-loading" style="display: none;">
                                <div class="hvnly-map-loader"><i class="fas fa-map-marked-alt"></i><span>Loading Properties Map...</span></div>
                            </div>
                        </div>
                    </div>
                `;
            } else {
                mapHtml = `
                    <div class="hvnly-map-view hvnly-leaflet-map" id="hvnly-map-view-leaflet" data-provider="leaflet" data-zoom="${mapZoom}" data-scroll-wheel="${showScrollWheel}" style="height: 550px; min-height: 550px;">
                        <div class="hvnly-map-container" style="height: 100%;">
                            <div id="hvnly-properties-map" class="hvnly-properties-map" data-zoom-control="${showZoomControl}" style="height: 100%; width: 100%;"></div>
                            ${showFullscreen ? `<button id="hvnly-leaflet-map-fullscreen-btn" class="hvnly-map-fullscreen-btn hvnly-leaflet-map-fullscreen-btn" title="Toggle Fullscreen" data-fullscreen-target="hvnly-properties-map"><i class="fas fa-expand"></i></button>` : ''}
                            <div class="hvnly-map-loading" style="display: none;">
                                <div class="hvnly-map-loader"><i class="fas fa-map-marked-alt"></i><span>Loading Properties Map...</span></div>
                            </div>
                        </div>
                    </div>
                `;
            }
            
            container.innerHTML = mapHtml;
            this.attachMapEvents();
        }
        
        removeExistingMapView() {
            const mapPlaceholder = document.getElementById('hvnly-map-placeholder');
            if (mapPlaceholder) {
                mapPlaceholder.innerHTML = '';
            }
        }
        
        toggleFullscreen() {
            const mapContainer = document.getElementById('hvnly-properties-map');
            
            if (!mapContainer) {
                return;
            }
            
            let fullscreenBtn;
            if (this.mapProvider === 'google') {
                fullscreenBtn = document.getElementById('hvnly-google-map-fullscreen-btn');
            } else {
                fullscreenBtn = document.getElementById('hvnly-leaflet-map-fullscreen-btn');
            }
            
            if (!fullscreenBtn) {
                return;
            }
            
            if (!document.fullscreenElement) {
                if (mapContainer.requestFullscreen) {
                    mapContainer.requestFullscreen();
                } else if (mapContainer.webkitRequestFullscreen) {
                    mapContainer.webkitRequestFullscreen();
                } else if (mapContainer.msRequestFullscreen) {
                    mapContainer.msRequestFullscreen();
                } else if (mapContainer.mozRequestFullScreen) {
                    mapContainer.mozRequestFullScreen();
                }
                
                fullscreenBtn.innerHTML = '<i class="fas fa-compress"></i>';
                fullscreenBtn.title = 'Exit Fullscreen';
            } else {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.webkitExitFullscreen) {
                    document.webkitExitFullscreen();
                } else if (document.msExitFullscreen) {
                    document.msExitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                }
                
                fullscreenBtn.innerHTML = '<i class="fas fa-expand"></i>';
                fullscreenBtn.title = 'Toggle Fullscreen';
            }
        }
        
        fetchPropertiesForMap() {
            const self = this;
            
            setTimeout(() => {
                const mapContainer = document.getElementById('hvnly-properties-map');
                if (!mapContainer) {
                    this.isLoading = false;
                    this.showMapError('Map container not found. Please try again.');
                    return;
                }
                
                const ajaxUrl = window.hvnly_PROPERTY_ajax?.ajax_url || window.ajaxurl;
                const ajaxNonce = window.hvnly_PROPERTY_ajax?.nonce;
                
                if (!ajaxUrl) {
                    this.isLoading = false;
                    this.showMapError('Configuration error: Unable to load map data.');
                    return;
                }
                
                const formData = new FormData();
                formData.append('action', 'hvnly_get_properties_for_map');
                formData.append('nonce', ajaxNonce);
                formData.append('page', this.currentPage);
                formData.append('per_page', this.propertiesPerPage);
                
                const currentFilters = window.havenlyticsAJAX?.getFormData ? window.havenlyticsAJAX.getFormData() : null;
                if (currentFilters) {
                    for (let key in currentFilters) {
                        if (key !== 'action' && key !== 'nonce' && key !== 'page' && key !== 'per_page') {
                            if (Array.isArray(currentFilters[key])) {
                                currentFilters[key].forEach(value => {
                                    formData.append(key + '[]', value);
                                });
                            } else {
                                formData.append(key, currentFilters[key]);
                            }
                        }
                    }
                } else {
                    this.collectAllFilterValues(formData);
                }
                
                const mapLoading = document.querySelector('.hvnly-map-loading');
                if (mapLoading) {
                    mapLoading.style.display = 'flex';
                }
                
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 10000);
                
                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData,
                    signal: controller.signal
                })
                .then(response => {
                    clearTimeout(timeoutId);
                    
                    if (!response.ok) {
                        return response.text().then(text => {
                            throw new Error(`HTTP error! status: ${response.status}, message: ${text}`);
                        });
                    }
                    return response.json();
                })
                .then(data => {
                    if (mapLoading) {
                        mapLoading.style.display = 'none';
                    }
                    
                    self.isLoading = false;
                    
                    if (data.success) {
                        if (data.data && data.data.properties) {
                            self.propertiesByPage[self.currentPage] = data.data.properties;
                            self.maxLoadedPage = Math.max(self.maxLoadedPage, self.currentPage);
                            self.maxPages = data.data.max_pages || 1;
                            self.totalProperties = data.data.found_posts || 0;
                            self.updateMainPaginationDisplay(data.data);
                            
                            if (data.data.properties.length > 0) {
                                if (self.currentPage === 1) {
                                    self.initializePropertiesMap(data.data.properties);
                                } else {
                                    self.addPropertiesToMap(data.data.properties);
                                }
                            } else {
                                if (self.currentPage === 1) {
                                    self.showMapError('No properties with valid location data found for your search criteria.');
                                }
                            }
                        } else {
                            self.showMapError('Invalid data received from server.');
                        }
                    } else {
                        self.showMapError('Server error: ' + (data.data || 'Unknown error'));
                    }
                })
                .catch(error => {
                    clearTimeout(timeoutId);
                    
                    if (mapLoading) {
                        mapLoading.style.display = 'none';
                    }
                    
                    self.isLoading = false;
                    
                    if (error.name === 'AbortError') {
                        self.showMapError('Request timed out. Please try again.');
                    } else {
                        const errorMessage = error.message || 'Unknown error occurred';
                        self.showMapError('Error loading map: ' + errorMessage);
                    }
                });
            }, 100);
        }
        
        collectAllFilterValues(formData) {
            const searchForm = $('#hvnly-property-search-form__box');
            if (searchForm.length) {
                const formElements = searchForm.find('input, select');
                formElements.each(function() {
                    const $element = $(this);
                    const name = $element.attr('name');
                    
                    if (name) {
                        if ($element.is(':checkbox')) {
                            if ($element.is(':checked')) {
                                formData.append(name, $element.val());
                            }
                        } else if ($element.is('select')) {
                            const value = $element.val();
                            if (value) {
                                formData.append(name, value);
                            }
                        } else {
                            const value = $element.val();
                            if (value) {
                                formData.append(name, value);
                            }
                        }
                    }
                });
            }
            
            const filterSidebar = $('#hvnly-filter-sidebar');
            if (filterSidebar.length) {
                filterSidebar.find('input[name="property_ids[]"]:checked').each(function() {
                    formData.append('property_ids[]', $(this).val());
                });
                
                filterSidebar.find('input[name="hvnly_prop_badges[]"]:checked').each(function() {
                    formData.append('hvnly_prop_badges[]', $(this).val());
                });

                const minPrice = filterSidebar.find('select[name="min_price"]').val();
                const maxPrice = filterSidebar.find('select[name="max_price"]').val();
                if (minPrice) formData.append('min_price', minPrice);
                if (maxPrice) formData.append('max_price', maxPrice);
                
                const bedrooms = filterSidebar.find('select[name="bedrooms"]').val();
                const reception_rooms = filterSidebar.find('select[name="reception_rooms"]').val();
                const bathrooms = filterSidebar.find('select[name="bathrooms"]').val();
                if (bedrooms) formData.append('bedrooms', bedrooms);
                if (bathrooms) formData.append('bathrooms', bathrooms);
                if (reception_rooms) formData.append('reception_rooms', reception_rooms);
                
                const garages = filterSidebar.find('select[name="garages"]').val();
                if (garages) formData.append('garages', garages);
                
                filterSidebar.find('input[name="amenities[]"]:checked').each(function() {
                    formData.append('amenities[]', $(this).val());
                });
                
                filterSidebar.find('input[name="hvnly_prop_depts[]"]:checked').each(function() {
                    formData.append('hvnly_prop_depts[]', $(this).val());
                });
                
                const taxonomies = ['hvnly_prop_types', 'hvnly_prop_locations', 'hvnly_prop_features', 'hvnly_prop_reviews', 'hvnly_prop_tags', 'hvnly_prop_status'];
                
                taxonomies.forEach(taxonomy => {
                    filterSidebar.find(`input[name="${taxonomy}[]"]:checked`).each(function() {
                        formData.append(`${taxonomy}[]`, $(this).val());
                    });
                });
            }
            
            const topSearchDropdowns = $('.hvnly-property-tax-multichebox');
            if (topSearchDropdowns.length) {
                topSearchDropdowns.find('input[name="property_type[]"]:checked').each(function() {
                    formData.append('hvnly_prop_types[]', $(this).val());
                });
                
                topSearchDropdowns.find('input[name="location[]"]:checked').each(function() {
                    formData.append('hvnly_prop_locations[]', $(this).val());
                });
            }
            
            const sortSelect = $('.hvnly-property-sort-select');
            if (sortSelect.length && sortSelect.val()) {
                formData.append('orderby', sortSelect.val());
            }
            
            const activeView = $('.hvnly-property-view-btn.active');
            if (activeView.length) {
                formData.append('view_type', activeView.data('view'));
            } else {
                formData.append('view_type', 'grid');
            }
            
            const department = $('#department').val();
            if (department) {
                formData.append('department', department);
            }
        }
        
        updateMainPaginationDisplay(data) {
            const resultsCount = $('#hvnly-results-count');
            if (resultsCount.length && data.results_count_html) {
                resultsCount.html(data.results_count_html);
            }
            
            if (window.havenlyticsAJAX && window.havenlyticsAJAX.modules &&
                window.havenlyticsAJAX.modules.pagination &&
                typeof window.havenlyticsAJAX.modules.pagination.updatePaginationDisplay === 'function') {
                
                window.havenlyticsAJAX.modules.pagination.updatePaginationDisplay(data);
            } else {
                const paginationContainer = $('#hvnly-property-pagination');
                if (paginationContainer.length && data.pagination_html) {
                    paginationContainer.html(data.pagination_html);
                }
                
                this.updateLoadMoreSection(data);
            }
            
            this.updateMapLoadMoreCount(data);
        }
        
        updateMapLoadMoreCount(data) {
            const loadedCount = $('#loadedCount');
            const totalCount = $('#totalCount');
            
            if (loadedCount.length && data.found_posts) {
                const cumulativeCount = Math.min(this.currentPage * this.propertiesPerPage, data.found_posts);
                loadedCount.text(cumulativeCount);
            }
            
            if (totalCount.length && data.found_posts) {
                totalCount.text(data.found_posts);
            }
        }
        
        updateLoadMoreSection(data) {
            const loadMoreContainer = $('#hvnly-load-more');
            if (!loadMoreContainer.length) return;
            this.maxPages = data.max_pages || 1;
            this.currentPage = data.current_page || 1;
            
            const shouldShowLoadMore = this.currentPage < this.maxPages;
            
            if (shouldShowLoadMore) {
                loadMoreContainer.show();
            } else {
                loadMoreContainer.hide();
            }
            
            this.updateMapLoadMoreCount(data);
        }
        
        loadMoreMapProperties() {
            if (this.isLoading || this.currentPage >= this.maxPages) return;
            this.fetchPropertiesForMap();
        }
        
        showMapPage(page) {
            this.loadCumulativeToPage(page);
        }
        
        initializePropertiesMap(properties) {
            const mapContainer = document.getElementById('hvnly-properties-map');
            
            if (!mapContainer) {
                this.showMapError('Map container not found during initialization.');
                return;
            }
            
            if (this.mapProvider === 'google' && typeof google === 'undefined') {
                this.showMapError('Google Maps library not loaded. Please refresh the page.');
                return;
            } else if ((this.mapProvider === 'leaflet' || this.mapProvider === 'openstreetmap') && typeof L === 'undefined') {
                this.showMapError('Map library not loaded. Please refresh the page.');
                return;
            }
            
            if (!properties || !properties.length) {
                this.showMapError('No properties available for map view.');
                return;
            }
            
            try {
                if (this.map) {
                    if (this.mapProvider === 'google') {
                        this.markers.forEach(marker => {
                            if (marker && typeof marker.setMap === 'function') {
                                marker.setMap(null);
                            }
                        });
                        this.markers = [];
                    } else {
                        if (this.map && typeof this.map.remove === 'function') {
                            this.map.remove();
                        }
                        this.markers = [];
                        this.clusterGroups = [];
                    }
                    this.map = null;
                }
                
                const validProperties = properties.filter(property => {
                    if (!property.lat || !property.lng) {
                        return false;
                    }
                    
                    const lat = parseFloat(property.lat);
                    const lng = parseFloat(property.lng);
                    
                    let adjustedLng = lng;
                    if (lng > 180) adjustedLng = lng - 360;
                    if (lng < -180) adjustedLng = lng + 360;
                    property.lng = adjustedLng;
                    
                    if (isNaN(lat) || isNaN(adjustedLng) || lat < -90 || lat > 90 || adjustedLng < -180 || adjustedLng > 180) {
                        return false;
                    }
                    
                    return true;
                });
                
                if (validProperties.length === 0) {
                    this.showMapError('No properties with valid location data found.');
                    return;
                }
                
                this.allMapProperties = validProperties;
                
                if (this.mapProvider === 'google') {
                    this.initializeGoogleMap(validProperties);
                } else {
                    this.initializeLeafletMap(validProperties);
                }
                
                this.isMapInitialized = true;
                
            } catch (error) {
                this.showMapError('Error initializing map: ' + error.message);
            }
        }
        
        initializeGoogleMap(properties) {
            const mapContainer = document.getElementById('hvnly-properties-map');
            const firstProperty = properties[0];
            const centerLat = parseFloat(firstProperty.lat);
            const centerLng = parseFloat(firstProperty.lng);
            const defaultZoom = parseInt(this.mapConfig.zoom_level) || 12;
            const mapType = this.mapConfig.google_map_type || 'roadmap';
            
            this.map = new google.maps.Map(mapContainer, {
                center: { lat: centerLat, lng: centerLng },
                zoom: defaultZoom,
                mapTypeId: mapType,
                fullscreenControl: false,
                zoomControl: this.mapConfig.show_zoom_control !== false,
                zoomControlOptions: { position: google.maps.ControlPosition.TOP_RIGHT },
                scrollwheel: this.mapConfig.show_scroll_wheel !== false
            });
            
            this.addGoogleMarkersToMap(properties);
            this.addGoogleMapControls();
        }
        
        initializeLeafletMap(properties) {
            const mapContainer = document.getElementById('hvnly-properties-map');
            const firstProperty = properties[0];
            const centerLat = parseFloat(firstProperty.lat);
            const centerLng = parseFloat(firstProperty.lng);
            const defaultZoom = parseInt(this.mapConfig.zoom_level) || 10;
            
            const tileUrl = this.mapConfig.osm_tile_url || 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
            const attribution = this.mapConfig.osm_attribution || '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
            
            if (mapContainer) {
                mapContainer.style.height = '550px';
                mapContainer.style.minHeight = '550px';
            }
            
            this.map = L.map('hvnly-properties-map', {
                zoomControl: false,
                scrollWheelZoom: this.mapConfig.show_scroll_wheel !== false
            }).setView([centerLat, centerLng], defaultZoom);
            
            L.tileLayer(tileUrl, {
                attribution: attribution,
                maxZoom: 19,
            }).addTo(this.map);
            
            if (this.mapConfig.show_zoom_control !== false) {
                L.control.zoom({ position: 'topright' }).addTo(this.map);
            }
            
            this.addMarkersToMap(properties);
            this.addMapControls(this.map);
        }
        
        addPropertiesToMap(properties) {
            if (!this.map) {
                return;
            }
            
            const validProperties = properties.filter(property => {
                if (!property.lat || !property.lng) return false;
                
                const lat = parseFloat(property.lat);
                const lng = parseFloat(property.lng);
                
                let adjustedLng = lng;
                if (lng > 180) adjustedLng = lng - 360;
                if (lng < -180) adjustedLng = lng + 360;
                property.lng = adjustedLng;
                
                if (isNaN(lat) || isNaN(adjustedLng) || lat < -90 || lat > 90 || adjustedLng < -180 || adjustedLng > 180) {
                    return false;
                }
                
                return true;
            });
            
            if (validProperties.length === 0) {
                return;
            }
            
            this.allMapProperties = this.allMapProperties.concat(validProperties);
            
            if (this.mapProvider === 'google') {
                this.addGoogleMarkersToMap(validProperties);
            } else {
                this.addMarkersToMap(validProperties);
            }
            
            setTimeout(() => this.updateMapBounds(), 100);
        }
        
        addGoogleMarkersToMap(properties) {
            if (!this.map) return;
            
            const markerColor = this.mapConfig.marker_color || '#6C60FE';
            
            const infoWindow = new google.maps.InfoWindow({
                maxWidth: 300,
                pixelOffset: new google.maps.Size(0, -5),
                disableAutoPan: false
            });
            
            properties.forEach((property) => {
                const lat = parseFloat(property.lat);
                const lng = parseFloat(property.lng);
                
                const svgMarker = {
                    path: `M21 0C9.4 0 0 9.4 0 21c0 11.6 9.4 21 21 21s21-9.4 21-21c0-11.6-9.4-21-21-21zm0 10c6.1 0 11 4.9 11 11s-4.9 11-11 11-11-4.9-11-11 4.9-11 11-11z`,
                    fillColor: markerColor,
                    fillOpacity: 1,
                    strokeColor: '#ffffff',
                    strokeWeight: 3,
                    scale: 1.2,
                    anchor: new google.maps.Point(21, 42),
                    labelOrigin: new google.maps.Point(21, 23)
                };
                
                const marker = new google.maps.Marker({
                    position: { lat: lat, lng: lng },
                    map: this.map,
                    title: property.title,
                    icon: svgMarker,
                    label: {
                        text: '🏠',
                        color: markerColor,
                        fontSize: '16px',
                        fontWeight: 'bold'
                    },
                    optimized: true,
                    animation: google.maps.Animation.DROP
                });
                
                const popupContent = this.createStyledPopupContent(property);
                
                marker.addListener('click', () => {
                    infoWindow.close();
                    infoWindow.setContent(popupContent);
                    infoWindow.open(this.map, marker);
                });
                
                this.markers.push(marker);
            });
            
            if (this.currentPage === 1 && this.markers.length > 0) {
                setTimeout(() => this.updateMapBounds(), 500);
            }
        }

        createStyledPopupContent(property) {
            const title = this.escapeHtml(property.title || 'Untitled Property');
            const price = property.price ? this.escapeHtml(property.price) : '';
            const address = property.address ? this.escapeHtml(property.address) : '';
            const bedrooms = property.bedrooms ? parseInt(property.bedrooms) : 0;
            const bathrooms = property.bathrooms ? parseInt(property.bathrooms) : 0;
            const thumbnail = property.thumbnail || '';
            const link = property.link || '#';
            
            return `
                <div class="hvnly-property-popup-content">
                    <div class="hvnly-popup-image">
                        ${thumbnail ? `<img src="${thumbnail}" alt="${title}" loading="lazy" onerror="this.parentElement.innerHTML='<div class=\'hvnly-popup-no-image\'><i class=\'fas fa-home\'></i></div>'">` : '<div class="hvnly-popup-no-image"><i class="fas fa-home"></i></div>'}
                    </div>
                    <div class="hvnly-popup-details">
                        <h4 class="hvnly-popup-title">${title}</h4>
                        ${price ? `<p class="hvnly-popup-price">${price}</p>` : ''}
                        ${address ? `<p class="hvnly-popup-address"><i class="fas fa-map-marker-alt"></i><span>${address}</span></p>` : ''}
                        <div class="hvnly-popup-features">
                            ${bedrooms > 0 ? `<div class="hvnly-popup-feature"><i class="fas fa-bed"></i> ${bedrooms} Bed</div>` : ''}
                            ${bathrooms > 0 ? `<div class="hvnly-popup-feature"><i class="fas fa-bath"></i> ${bathrooms} Bath</div>` : ''}
                        </div>
                        <div class="hvnly-popup-actions">
                            <a href="${link}" class="hvnly-popup-view-btn" target="_blank">
                                View Details <i class="fas fa-arrow-right"></i>
                            </a>
                        </div>
                    </div>
                </div>
            `;
        }

        escapeHtml(str) {
            if (!str) return '';
            const div = document.createElement('div');
            div.textContent = str;
            return div.innerHTML;
        }
        
        addMarkersToMap(properties) {
            if (!this.map) return;
            
            const useMarkerCluster = this.mapConfig.cluster_markers !== false && typeof L.markerClusterGroup !== 'undefined';
            const markerColor = this.mapConfig.marker_color || '#6C60FE';
            
            let markersLayer;
            if (useMarkerCluster && this.clusterGroups.length > 0) {
                markersLayer = this.clusterGroups[0];
            } else if (useMarkerCluster) {
                markersLayer = L.markerClusterGroup({
                    chunkedLoading: true,
                    maxClusterRadius: 50,
                    spiderfyOnMaxZoom: true,
                    showCoverageOnHover: true,
                    zoomToBoundsOnClick: true,
                    iconCreateFunction: function(cluster) {
                        const childCount = cluster.getChildCount();
                        let size = 'small';
                        if (childCount > 100) size = 'large';
                        else if (childCount > 10) size = 'medium';
                        
                        return L.divIcon({
                            html: `<div><span>${childCount}</span></div>`,
                            className: `marker-cluster marker-cluster-${size}`,
                            iconSize: L.point(40, 40)
                        });
                    }
                });
                
                this.clusterGroups.push(markersLayer);
                this.map.addLayer(markersLayer);
            } else {
                markersLayer = this.map;
            }
            
            properties.forEach((property) => {
                const lat = parseFloat(property.lat);
                const lng = parseFloat(property.lng);
                
                const customIcon = L.divIcon({
                    className: 'custom-leaflet-marker',
                    html: `<div class="custom-marker-pin"><div class="marker-pin" style="background: ${markerColor}"><i class="fas fa-home" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(45deg); color: white; font-size: 14px;"></i></div><div class="marker-shadow"></div></div>`,
                    iconSize: [42, 42],
                    iconAnchor: [21, 42],
                    popupAnchor: [0, -42]
                });
                
                const marker = L.marker([lat, lng], {
                    icon: customIcon,
                    propertyId: property.id
                });
                
                const popupContent = this.createStyledPopupContent(property);
                
                marker.bindPopup(popupContent, { 
                    maxWidth: 300, 
                    minWidth: 280,
                    className: 'hvnly-property-popup',
                    autoPan: true,
                    autoPanPadding: L.point(50, 50)
                });
                
                this.markers.push(marker);
                
                if (useMarkerCluster) {
                    markersLayer.addLayer(marker);
                } else {
                    marker.addTo(markersLayer);
                }
            });
            
            if (this.currentPage === 1 && this.markers.length > 0) {
                setTimeout(() => this.updateMapBounds(), 500);
            }
        }
        
        updateMapBounds() {
            if (!this.map || this.markers.length === 0) return;
            
            try {
                if (this.mapProvider === 'google') {
                    if (typeof google !== 'undefined' && google.maps) {
                        const bounds = new google.maps.LatLngBounds();
                        this.markers.forEach(marker => {
                            if (marker && typeof marker.getPosition === 'function') {
                                const position = marker.getPosition();
                                if (position) bounds.extend(position);
                            }
                        });
                        if (!bounds.isEmpty()) {
                            this.map.fitBounds(bounds, { top: 50, right: 50, bottom: 50, left: 50 });
                        }
                    }
                } else {
                    if (this.map && typeof this.map.invalidateSize === 'function') {
                        this.map.invalidateSize();
                    }
                    if (typeof L !== 'undefined') {
                        const bounds = L.latLngBounds(this.markers.map(marker => {
                            if (marker && typeof marker.getLatLng === 'function') {
                                return marker.getLatLng();
                            }
                            return null;
                        }).filter(b => b));
                        
                        if (bounds && bounds.isValid && bounds.isValid()) {
                            this.map.fitBounds(bounds, { padding: [50, 50], maxZoom: 15 });
                        }
                    }
                }
            } catch (boundsError) {}
        }
        
        addMapControls(map) {
            try {
                L.control.zoom({ position: 'topright' }).addTo(map);
            } catch (controlError) {}
            
            const self = this;
            const fullscreenControl = L.control({ position: 'topright' });
            
            fullscreenControl.onAdd = function(map) {
                const div = L.DomUtil.create('div', 'leaflet-control leaflet-control-custom');
                const fullscreenButton = document.createElement('a');
                fullscreenButton.id = 'hvnly-leaflet-map-fullscreen-btn';
                fullscreenButton.href = '#';
                fullscreenButton.title = 'Toggle Fullscreen';
                fullscreenButton.className = 'custom-fullscreen-button';
                fullscreenButton.innerHTML = '<i class="fas fa-expand"></i>';
                
                L.DomEvent.disableClickPropagation(fullscreenButton);
                
                fullscreenButton.addEventListener('click', (e) => {
                    e.preventDefault();
                    self.toggleFullscreen();
                });
                
                div.appendChild(fullscreenButton);
                return div;
            };
            
            fullscreenControl.addTo(map);
        }
        
        addGoogleMapControls() {
            const controlContainer = document.createElement('div');
            controlContainer.className = 'hvnly-google-map-controls-container';
            const fullscreenButton = document.createElement('div');
            fullscreenButton.id = 'hvnly-google-map-fullscreen-btn';
            fullscreenButton.className = 'hvnly-map-fullscreen-btn hvnly-google-map-fullscreen-btn';
            fullscreenButton.innerHTML = '<i class="fas fa-expand"></i>';
            fullscreenButton.title = 'Toggle Fullscreen';
            
            fullscreenButton.addEventListener('click', () => {
                this.toggleFullscreen();
            });
            
            controlContainer.appendChild(fullscreenButton);
            this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(controlContainer);
        }
        
        showMapError(message) {
            const mapView = document.querySelector('.hvnly-map-view');
            if (mapView) {
                mapView.innerHTML = `
                    <div class="hvnly-map-error">
                        <div class="hvnly-map-error-icon">
                            <i class="fas fa-exclamation-triangle"></i>
                        </div>
                        <h3>Map Unavailable</h3>
                        <p>${message}</p>
                        <button class="hvnly-retry-map-btn" onclick="window.HavenlyticsPropertyMap.loadPropertyMap()">
                            <i class="fas fa-redo"></i> Retry
                        </button>
                    </div>
                `;
            }
        }
        
        onGoogleMapsReady() {
            if (this.mapProvider === 'google' && !this.isMapInitialized && this.allMapProperties.length > 0) {
                this.initializeGoogleMap(this.allMapProperties);
            }
        }
        
        onGoogleMapsAuthFailure() {
            if (this.map) {
                if (this.markers) {
                    this.markers.forEach(marker => {
                        if (marker && typeof marker.setMap === 'function') {
                            marker.setMap(null);
                        }
                    });
                }
                this.map = null;
            }
            
            this.mapProvider = 'leaflet';
            this.markers = [];
            this.clusterGroups = [];
            this.isMapInitialized = false;
            this.loadPropertyMap();
        }
    }
    
    $(document).ready(function() {
        if (typeof $ === 'undefined') {
            return;
        }
        
        setTimeout(function() {
            window.HavenlyticsPropertyMap = new HavenlyticsPropertyMap();
            window.HvnlyPropertyMap = window.HavenlyticsPropertyMap;
        }, 100);
    });
    
    window.gm_authFailure = function() {
        const mapInstance = window.HavenlyticsPropertyMap || window.HvnlyPropertyMap;
        if (mapInstance && typeof mapInstance.onGoogleMapsAuthFailure === 'function') {
            mapInstance.onGoogleMapsAuthFailure();
        } else if (mapInstance) {
            mapInstance.mapProvider = 'leaflet';
            if (mapInstance.loadPropertyMap) {
                mapInstance.loadPropertyMap();
            }
        }
    };
})(jQuery);