/**
 * MapHandler Class
 * 
 * Manages the map display and interactions.
 * Handles markers, info windows, and map events.
 */
class MapHandler {
    /**
     * Constructor for MapHandler
     * @param {Object} options - Configuration options
     * @param {string} options.containerId - ID of the map container element
     * @param {Function} options.onMarkerClick - Callback function when a marker is clicked
     * @param {boolean} options.debug - Enable debug logging
     */
    constructor(options = {}) {
        this.options = {
            containerId: 'map',
            mapOptions: {
                zoom: 12,
                center: { lat: 35.7219, lng: 51.3347 }, // Tehran default
                mapTypeId: 'roadmap',
                styles: [], // Custom map styles can be added here
                zoomControl: true,
                mapTypeControl: false,
                scaleControl: true,
                streetViewControl: false,
                rotateControl: false,
                fullscreenControl: true
            },
            markerOptions: {
                animation: google.maps.Animation.DROP
            },
            clusterOptions: {
                imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m',
                gridSize: 50,
                zoomOnClick: true,
                maxZoom: 15,
                minimumClusterSize: 2
            },
            debug: false,
            ...options
        };
        
        this.mapContainer = document.getElementById(this.options.containerId);
        
        if (!this.mapContainer) {
            console.error(`Map container with ID "${this.options.containerId}" not found`);
            return;
        }
        
        // Initialize properties
        this.map = null;
        this.markers = new Map(); // Map object to store markers by ID
        this.markerCluster = null;
        this.infoWindow = new google.maps.InfoWindow();
        this.bounds = new google.maps.LatLngBounds();
        this.highlightedMarker = null;
        this.loadingIndicator = null;
        this.onMarkerClick = options.onMarkerClick || (() => {});
        
        // Initialize the map
        this.initMap();
    }
    
    /**
     * Initialize the Google Map
     */
    initMap() {
        try {
            // Create the map instance
            this.map = new google.maps.Map(this.mapContainer, this.options.mapOptions);
            
            // Add map event listeners
            this.map.addListener('click', () => {
                this.infoWindow.close();
            });
            
            // Create a loading indicator
            this.createLoadingIndicator();
            
            this.log('Map initialized');
        } catch (error) {
            console.error('Error initializing map:', error);
        }
    }
    
    /**
     * Create a loading indicator for the map
     */
    createLoadingIndicator() {
        this.loadingIndicator = document.createElement('div');
        this.loadingIndicator.className = 'map-loading-indicator';
        this.loadingIndicator.innerHTML = '<div class="spinner"></div>';
        this.loadingIndicator.style.display = 'none';
        
        if (this.mapContainer.parentNode) {
            this.mapContainer.parentNode.appendChild(this.loadingIndicator);
        } else {
            // Fallback to appending to the map container itself
            this.mapContainer.appendChild(this.loadingIndicator);
        }
    }
    
    /**
     * Show the loading indicator
     */
    showLoadingIndicator() {
        if (this.loadingIndicator) {
            this.loadingIndicator.style.display = 'flex';
        }
    }
    
    /**
     * Hide the loading indicator
     */
    hideLoadingIndicator() {
        if (this.loadingIndicator) {
            this.loadingIndicator.style.display = 'none';
        }
    }
    
    /**
     * Add a single location to the map
     * @param {Object} location - Location data object
     * @returns {google.maps.Marker} The created marker
     */
    addLocation(location) {
        if (!location || !location.id || !location.latitude || !location.longitude) {
            console.warn('Invalid location data:', location);
            return null;
        }
        
        // Check if marker already exists
        if (this.markers.has(location.id)) {
            return this.markers.get(location.id);
        }
        
        try {
            const position = new google.maps.LatLng(
                parseFloat(location.latitude),
                parseFloat(location.longitude)
            );
            
            // Determine icon based on category
            let icon = null;
            if (location.category) {
                icon = this.getCategoryIcon(location.category);
            }
            
            // Create marker
            const marker = new google.maps.Marker({
                position: position,
                map: this.map,
                title: location.name,
                icon: icon,
                animation: this.options.markerOptions.animation,
                optimized: true
            });
            
            // Store location data with marker
            marker.locationData = location;
            
            // Add click listener
            marker.addListener('click', () => {
                this.handleMarkerClick(marker);
            });
            
            // Store marker
            this.markers.set(location.id, marker);
            
            // Extend bounds
            this.bounds.extend(position);
            
            return marker;
        } catch (error) {
            console.error(`Error adding marker for location ${location.id}:`, error);
            return null;
        }
    }
    
    /**
     * Add multiple locations to the map
     * @param {Array} locations - Array of location data objects
     */
    addLocations(locations) {
        if (!Array.isArray(locations)) {
            console.warn('Invalid locations array:', locations);
            return;
        }
        
        this.log(`Adding ${locations.length} locations to map`);
        
        // Clear existing markers
        this.clearLocations();
        
        // Add all locations
        locations.forEach(location => {
            this.addLocation(location);
        });
        
        // Update marker clusters if enabled
        this.updateMarkerClusters();
        
        // Fit bounds if we have markers
        if (this.markers.size > 0) {
            this.fitBounds();
        }
    }
    
    /**
     * Clear all locations from the map
     */
    clearLocations() {
        // Remove marker clusters
        if (this.markerCluster) {
            this.markerCluster.clearMarkers();
            this.markerCluster = null;
        }
        
        // Clear all markers
        this.markers.forEach(marker => {
            marker.setMap(null);
        });
        
        // Reset collections
        this.markers.clear();
        this.bounds = new google.maps.LatLngBounds();
        this.highlightedMarker = null;
        
        // Close info window
        this.infoWindow.close();
        
        this.log('Cleared all locations from map');
    }
    
    /**
     * Update marker clusters
     */
    updateMarkerClusters() {
        // Clear existing clusters
        if (this.markerCluster) {
            this.markerCluster.clearMarkers();
        }
        
        // Create marker array from map
        const markersArray = Array.from(this.markers.values());
        
        if (markersArray.length > 0) {
            // Create new cluster
            this.markerCluster = new MarkerClusterer(
                this.map,
                markersArray,
                this.options.clusterOptions
            );
            
            this.log(`Created marker cluster with ${markersArray.length} markers`);
        }
    }
    
    /**
     * Handle marker click event
     * @param {google.maps.Marker} marker - The clicked marker
     */
    handleMarkerClick(marker) {
        if (!marker || !marker.locationData) return;
        
        // Open info window
        this.showInfoWindow(marker.locationData);
        
        // Highlight marker
        this.highlightMarker(marker.locationData.id);
        
        // Call external callback
        if (typeof this.onMarkerClick === 'function') {
            this.onMarkerClick(marker.locationData);
        }
    }
    
    /**
     * Show info window for a location
     * @param {Object} location - Location data object
     */
    showInfoWindow(location) {
        if (!location) return;
        
        // Get marker for this location
        const marker = this.markers.get(location.id);
        if (!marker) return;
        
        // Build info window content
        const content = this.buildInfoWindowContent(location);
        
        // Set content and open
        this.infoWindow.setContent(content);
        this.infoWindow.open(this.map, marker);
    }
    
    /**
     * Build HTML content for info window
     * @param {Object} location - Location data object
     * @returns {string} HTML content for info window
     */
    buildInfoWindowContent(location) {
        let categoryName = '';
        if (location.category) {
            if (typeof location.category === 'object') {
                categoryName = location.category.name || '';
            } else {
                categoryName = location.category;
            }
        }
        
        return `
            <div class="info-window">
                <h3>${location.name}</h3>
                ${categoryName ? `<p class="category">${categoryName}</p>` : ''}
                ${location.address ? `<p class="address">${location.address}</p>` : ''}
                <div class="info-window-actions">
                    <a href="#" class="view-details" onclick="showLocationDetails(${location.id}); return false;">View Details</a>
                </div>
            </div>
        `;
    }
    
    /**
     * Highlight a marker on the map
     * @param {string|number} locationId - ID of the location to highlight
     */
    highlightMarker(locationId) {
        // Reset previously highlighted marker
        if (this.highlightedMarker) {
            // Restore original icon and zIndex
            const prevMarker = this.markers.get(this.highlightedMarker);
            if (prevMarker) {
                prevMarker.setZIndex(undefined);
                if (prevMarker.originalIcon) {
                    prevMarker.setIcon(prevMarker.originalIcon);
                }
            }
            this.highlightedMarker = null;
        }
        
        // Highlight new marker
        const marker = this.markers.get(locationId);
        if (marker) {
            // Store original icon if not already stored
            if (!marker.originalIcon && marker.getIcon()) {
                marker.originalIcon = marker.getIcon();
            }
            
            // Create highlighted icon
            const highlightedIcon = this.getHighlightedIcon(marker.locationData.category);
            
            // Apply highlighted state
            marker.setIcon(highlightedIcon);
            marker.setZIndex(1000); // Bring to front
            
            // Store current highlighted marker ID
            this.highlightedMarker = locationId;
            
            this.log(`Highlighted marker for location ${locationId}`);
        }
    }
    
    /**
     * Get icon URL based on category
     * @param {Object|string} category - Category object or string
     * @returns {Object} Google Maps icon object
     */
    getCategoryIcon(category) {
        let categoryId;
        
        if (typeof category === 'object' && category !== null) {
            categoryId = category.id;
        } else if (typeof category === 'string' || typeof category === 'number') {
            categoryId = category;
        } else {
            return null;
        }
        
        // Define icon mappings based on category IDs
        const iconMappings = {
            1: '/images/markers/hotel.png',       // مراکز اقامتی
            2: '/images/markers/shopping.png',    // مراکز خرید
            3: '/images/markers/medical.png',     // مراکز درمانی
            // Add more category mappings as needed
        };
        
        const iconUrl = iconMappings[categoryId] || '/images/markers/default.png';
        
        return {
            url: iconUrl,
            size: new google.maps.Size(32, 32),
            origin: new google.maps.Point(0, 0),
            anchor: new google.maps.Point(16, 32),
            scaledSize: new google.maps.Size(32, 32)
        };
    }
    
    /**
     * Get highlighted version of an icon
     * @param {Object|string} category - Category object or string
     * @returns {Object} Google Maps icon object for highlighted state
     */
    getHighlightedIcon(category) {
        const baseIcon = this.getCategoryIcon(category);
        
        // If no base icon, return default highlighted icon
        if (!baseIcon) {
            return {
                url: '/images/markers/highlighted.png',
                size: new google.maps.Size(40, 40),
                origin: new google.maps.Point(0, 0),
                anchor: new google.maps.Point(20, 40),
                scaledSize: new google.maps.Size(40, 40)
            };
        }
        
        // Create a larger version of the base icon
        return {
            ...baseIcon,
            size: new google.maps.Size(40, 40),
            anchor: new google.maps.Point(20, 40),
            scaledSize: new google.maps.Size(40, 40)
        };
    }
    
    /**
     * Fit the map bounds to include all markers
     */
    fitBounds() {
        if (this.markers.size === 0) return;
        
        this.map.fitBounds(this.bounds);
        
        // If we have just one marker, zoom out a bit
        if (this.markers.size === 1) {
            const currentZoom = this.map.getZoom();
            this.map.setZoom(currentZoom > 16 ? 16 : currentZoom);
        }
    }
    
    /**
     * Pan the map to a specific location
     * @param {Object} location - Location data object
     */
    panToLocation(location) {
        if (!location || !location.latitude || !location.longitude) return;
        
        const position = new google.maps.LatLng(
            parseFloat(location.latitude),
            parseFloat(location.longitude)
        );
        
        this.map.panTo(position);
        
        // Zoom in if we're too far out
        if (this.map.getZoom() < 14) {
            this.map.setZoom(15);
        }
    }
    
    /**
     * Log debug messages if debug is enabled
     * @param {string} message - Debug message
     * @param {*} data - Optional data to log
     */
    log(message, data) {
        if (this.options.debug) {
            if (data !== undefined) {
                console.log(`[MapHandler] ${message}`, data);
            } else {
                console.log(`[MapHandler] ${message}`);
            }
        }
    }
}

// Make the map handler globally available
window.mapHandler = null;

// Initialize when the Google Maps API is loaded
function initMapHandler() {
    window.mapHandler = new MapHandler({
        // Custom options can be added here
        infoWindowTemplate: (location) => {
            // Create a rich info window content
            let categoryName = '';
            if (location.category && typeof location.category === 'object') {
                categoryName = location.category.name || location.category.title || '';
            } else if (typeof location.category === 'string') {
                categoryName = location.category;
            }
            
            return `
                <div class="map-info-window">
                    <div class="info-header">
                        <h3>${location.title || 'Unnamed Location'}</h3>
                        ${categoryName ? `<span class="category-badge">${categoryName}</span>` : ''}
                    </div>
                    
                    ${location.image ? `
                        <div class="info-image">
                            <img src="${location.image}" alt="${location.title}">
                        </div>
                    ` : ''}
                    
                    <div class="info-content">
                        ${location.address ? `
                            <div class="info-item">
                                <i class="fas fa-map-marker-alt"></i>
                                <span>${location.address}</span>
                            </div>
                        ` : ''}
                        
                        ${location.phone ? `
                            <div class="info-item">
                                <i class="fas fa-phone"></i>
                                <span>${location.phone}</span>
                            </div>
                        ` : ''}
                        
                        ${location.email ? `
                            <div class="info-item">
                                <i class="fas fa-envelope"></i>
                                <span>${location.email}</span>
                            </div>
                        ` : ''}
                        
                        ${location.website ? `
                            <div class="info-item">
                                <i class="fas fa-globe"></i>
                                <a href="${location.website}" target="_blank">Visit Website</a>
                            </div>
                        ` : ''}
                    </div>
                    
                    ${location.description ? `
                        <div class="info-description">
                            <p>${location.description}</p>
                        </div>
                    ` : ''}
                    
                    <div class="info-actions">
                        <a href="https://www.google.com/maps/dir/?api=1&destination=${location.lat},${location.lng}" 
                           target="_blank" class="directions-btn">
                            <i class="fas fa-directions"></i> Get Directions
                        </a>
                    </div>
                </div>
            `;
        }
    });
}

// Initialize map handler when Google Maps API is ready
if (typeof google !== 'undefined' && google.maps) {
    initMapHandler();
} else {
    // Set up callback for Google Maps API to call when loaded
    window.initMapHandler = initMapHandler; 
} 