// Map and visualization management module
export class MapManager {
    constructor() {
        this.map = null;
        this.coverageMap = null;
        this.mapOrigin = null;
        
        // Source markers and overlays
        this.sourceMarkers = new Map();
        this.rangeCircles = new Map();
        this.showSources = true;
        this.showRange = false;
        this.selectedSource = null;
        this.heatmapLayer = null;
        
        // Data references
        this.sourcesData = new Map();
        
        // Map theme
        this.isDarkMode = false;
        this.currentTileLayer = null;
        this.coverageTileLayer = null;
    }

    async initializeMap() {
        // Get origin from server
        let origin = { latitude: 51.4700, longitude: -0.4600 }; // fallback
        try {
            const response = await fetch('/api/origin');
            if (response.ok) {
                origin = await response.json();
            }
        } catch (error) {
            console.warn('Could not fetch origin, using default:', error);
        }
        
        // Store origin for reset functionality
        this.mapOrigin = origin;
        
        this.map = L.map('map').setView([origin.latitude, origin.longitude], 10);
        
        // Light tile layer by default
        this.currentTileLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
            subdomains: 'abcd',
            maxZoom: 19
        }).addTo(this.map);
        
        // Add scale control for distance estimation
        L.control.scale({
            metric: true,
            imperial: true,
            position: 'bottomright'
        }).addTo(this.map);
        
        return this.map;
    }

    async initializeCoverageMap() {
        if (!this.coverageMap) {
            // Get origin from server
            let origin = { latitude: 51.4700, longitude: -0.4600 }; // fallback
            try {
                const response = await fetch('/api/origin');
                if (response.ok) {
                    origin = await response.json();
                }
            } catch (error) {
                console.warn('Could not fetch origin for coverage map, using default:', error);
            }
            
            this.coverageMap = L.map('coverage-map').setView([origin.latitude, origin.longitude], 10);
            
            this.coverageTileLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
                attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            }).addTo(this.coverageMap);
            
            // Add scale control for distance estimation
            L.control.scale({
                metric: true,
                imperial: true,
                position: 'bottomright'
            }).addTo(this.coverageMap);
        }
        
        return this.coverageMap;
    }

    updateSourcesData(data) {
        if (data.sources) {
            this.sourcesData.clear();
            data.sources.forEach(source => {
                this.sourcesData.set(source.id, source);
            });
        }
    }

    updateSourceMarkers() {
        if (!this.map || !this.showSources) return;
        
        // Remove markers for sources that no longer exist
        const currentSourceIds = new Set(this.sourcesData.keys());
        for (const [id, marker] of this.sourceMarkers) {
            if (!currentSourceIds.has(id)) {
                this.map.removeLayer(marker);
                this.sourceMarkers.delete(id);
            }
        }
        
        // Update or create markers for current sources
        for (const [id, source] of this.sourcesData) {
            if (source.latitude && source.longitude) {
                if (this.sourceMarkers.has(id)) {
                    // Update existing marker
                    const marker = this.sourceMarkers.get(id);
                    
                    // Update marker style if status changed
                    marker.setStyle({
                        radius: source.active ? 10 : 6,
                        fillColor: source.active ? '#00d4ff' : '#666666',
                        fillOpacity: 0.8
                    });
                    
                    // Update popup content if it's open
                    if (marker.isPopupOpen()) {
                        marker.setPopupContent(this.createSourcePopupContent(source));
                    }
                } else {
                    // Create new marker
                    const marker = L.circleMarker([source.latitude, source.longitude], {
                        radius: source.active ? 10 : 6,
                        fillColor: source.active ? '#00d4ff' : '#666666',
                        color: '#ffffff',
                        weight: 2,
                        fillOpacity: 0.8,
                        className: 'source-marker'
                    }).addTo(this.map);
                    
                    marker.bindPopup(this.createSourcePopupContent(source), {
                        maxWidth: 300
                    });
                    
                    this.sourceMarkers.set(id, marker);
                }
            }
        }
        
        this.updateSourcesLegend();
    }

    updateRangeCircles() {
        if (!this.map || !this.showRange) return;
        
        // Clear existing circles
        this.rangeCircles.forEach(circle => this.map.removeLayer(circle));
        this.rangeCircles.clear();
        
        // Add range circles for active sources
        for (const [id, source] of this.sourcesData) {
            if (source.active && source.latitude && source.longitude) {
                // Add multiple range circles (50km, 100km, 200km)
                const ranges = [50000, 100000, 200000];
                ranges.forEach((range, index) => {
                    const circle = L.circle([source.latitude, source.longitude], {
                        radius: range,
                        fillColor: 'transparent',
                        color: '#00d4ff',
                        weight: 2,
                        opacity: 0.7 - (index * 0.15),
                        dashArray: '8,4'
                    }).addTo(this.map);
                    
                    this.rangeCircles.set(`${id}_${range}`, circle);
                });
            }
        }
    }

    createSourcePopupContent(source, aircraftData) {
        const aircraftCount = aircraftData ? Array.from(aircraftData.values())
            .filter(aircraft => aircraft.sources && aircraft.sources[source.id]).length : 0;
        
        return `
            <div class="source-popup">
                <h3>${source.name}</h3>
                <p><strong>ID:</strong> ${source.id}</p>
                <p><strong>Location:</strong> ${source.latitude.toFixed(4)}°, ${source.longitude.toFixed(4)}°</p>
                <p><strong>Status:</strong> ${source.active ? 'Active' : 'Inactive'}</p>
                <p><strong>Aircraft:</strong> ${aircraftCount}</p>
                <p><strong>Messages:</strong> ${source.messages || 0}</p>
                <p><strong>Last Seen:</strong> ${source.last_seen ? new Date(source.last_seen).toLocaleString() : 'N/A'}</p>
            </div>
        `;
    }

    updateSourcesLegend() {
        const legend = document.getElementById('sources-legend');
        if (!legend) return;
        
        legend.innerHTML = '';
        
        for (const [id, source] of this.sourcesData) {
            const item = document.createElement('div');
            item.className = 'legend-item';
            item.innerHTML = `
                <span class="legend-icon" style="background: ${source.active ? '#00d4ff' : '#666666'}"></span>
                <span title="${source.host}:${source.port}">${source.name}</span>
            `;
            legend.appendChild(item);
        }
    }

    resetMap() {
        if (this.mapOrigin && this.map) {
            this.map.setView([this.mapOrigin.latitude, this.mapOrigin.longitude], 10);
        }
    }

    toggleRangeCircles() {
        this.showRange = !this.showRange;
        
        if (this.showRange) {
            this.updateRangeCircles();
        } else {
            this.rangeCircles.forEach(circle => this.map.removeLayer(circle));
            this.rangeCircles.clear();
        }
        
        return this.showRange;
    }

    toggleSources() {
        this.showSources = !this.showSources;
        
        if (this.showSources) {
            this.updateSourceMarkers();
        } else {
            this.sourceMarkers.forEach(marker => this.map.removeLayer(marker));
            this.sourceMarkers.clear();
        }
        
        return this.showSources;
    }

    toggleDarkMode() {
        this.isDarkMode = !this.isDarkMode;
        
        const lightUrl = 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png';
        const darkUrl = 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png';
        const tileUrl = this.isDarkMode ? darkUrl : lightUrl;
        
        const tileOptions = {
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
            subdomains: 'abcd',
            maxZoom: 19
        };
        
        // Update main map
        if (this.map && this.currentTileLayer) {
            this.map.removeLayer(this.currentTileLayer);
            this.currentTileLayer = L.tileLayer(tileUrl, tileOptions).addTo(this.map);
        }
        
        // Update coverage map
        if (this.coverageMap && this.coverageTileLayer) {
            this.coverageMap.removeLayer(this.coverageTileLayer);
            this.coverageTileLayer = L.tileLayer(tileUrl, {
                attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            }).addTo(this.coverageMap);
        }
        
        return this.isDarkMode;
    }

    // Coverage map methods
    updateCoverageControls() {
        const select = document.getElementById('coverage-source');
        if (!select) return;
        
        select.innerHTML = '<option value="">Select Source</option>';
        
        for (const [id, source] of this.sourcesData) {
            const option = document.createElement('option');
            option.value = id;
            option.textContent = source.name;
            select.appendChild(option);
        }
    }

    async updateCoverageDisplay() {
        if (!this.selectedSource || !this.coverageMap) return;
        
        try {
            const response = await fetch(`/api/coverage/${this.selectedSource}`);
            const data = await response.json();
            
            // Clear existing coverage markers
            this.coverageMap.eachLayer(layer => {
                if (layer instanceof L.CircleMarker) {
                    this.coverageMap.removeLayer(layer);
                }
            });
            
            // Add coverage points
            data.points.forEach(point => {
                const intensity = Math.max(0, (point.signal + 50) / 50); // Normalize signal strength
                L.circleMarker([point.lat, point.lon], {
                    radius: 3,
                    fillColor: this.getSignalColor(point.signal),
                    color: 'white',
                    weight: 1,
                    fillOpacity: intensity
                }).addTo(this.coverageMap);
            });
            
        } catch (error) {
            console.error('Failed to load coverage data:', error);
        }
    }

    async toggleHeatmap() {
        if (!this.selectedSource) {
            alert('Please select a source first');
            return false;
        }
        
        if (this.heatmapLayer) {
            this.coverageMap.removeLayer(this.heatmapLayer);
            this.heatmapLayer = null;
            return false;
        } else {
            try {
                const response = await fetch(`/api/heatmap/${this.selectedSource}`);
                const data = await response.json();
                
                // Create heatmap layer (simplified)
                this.createHeatmapOverlay(data);
                return true;
                
            } catch (error) {
                console.error('Failed to load heatmap data:', error);
                return false;
            }
        }
    }

    getSignalColor(signal) {
        if (signal > -10) return '#00ff88';
        if (signal > -20) return '#ffff00';
        if (signal > -30) return '#ff8c00';
        return '#ff4444';
    }

    createHeatmapOverlay(data) {
        // Simplified heatmap implementation
        // In production, would use proper heatmap library like Leaflet.heat
    }

    setSelectedSource(sourceId) {
        this.selectedSource = sourceId;
    }

    getSourcePositions() {
        const positions = [];
        for (const [id, source] of this.sourcesData) {
            if (source.latitude && source.longitude) {
                positions.push([source.latitude, source.longitude]);
            }
        }
        return positions;
    }
}