// Import Three.js modules
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

class SkyView {
    constructor() {
        this.map = null;
        this.coverageMap = null;
        this.radar3d = null;
        this.websocket = null;
        
        // Data storage
        this.aircraftData = new Map();
        this.sourcesData = new Map();
        this.stats = {};
        
        // Map markers and overlays
        this.aircraftMarkers = new Map();
        this.sourceMarkers = new Map();
        this.aircraftTrails = new Map();
        this.rangeCircles = new Map();
        this.heatmapLayer = null;
        
        // UI state
        this.currentView = 'map-view';
        this.showTrails = false;
        this.showRange = false;
        this.showSources = true;
        this.selectedSource = null;
        
        // Charts
        this.charts = {};
        
        // Update tracking
        this.lastUpdateTime = new Date();
        
        this.init();
    }

    async init() {
        try {
            this.initializeViews();
            this.initializeMap();
            await this.initializeWebSocket();
            this.initializeEventListeners();
            this.initializeCharts();
            this.initializeClocks();
            this.initialize3DRadar();
            
            this.startPeriodicTasks();
        } catch (error) {
            console.error('Initialization failed:', error);
            this.showError('Failed to initialize application');
        }
    }

    // View Management
    initializeViews() {
        const viewButtons = document.querySelectorAll('.view-btn');
        const views = document.querySelectorAll('.view');

        viewButtons.forEach(btn => {
            btn.addEventListener('click', () => {
                const viewId = btn.id.replace('-btn', '');
                this.switchView(viewId);
            });
        });
    }

    switchView(viewId) {
        // Update buttons
        document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active'));
        const activeBtn = document.getElementById(`${viewId}-btn`);
        if (activeBtn) {
            activeBtn.classList.add('active');
        }
        
        // Update views (viewId already includes the full view ID like "map-view")
        document.querySelectorAll('.view').forEach(view => view.classList.remove('active'));
        const activeView = document.getElementById(viewId);
        if (activeView) {
            activeView.classList.add('active');
        } else {
            console.warn(`View element not found: ${viewId}`);
            return;
        }
        
        this.currentView = viewId;
        
        // Handle view-specific initialization (extract base name for switch)
        const baseName = viewId.replace('-view', '');
        switch (baseName) {
            case 'coverage':
                this.initializeCoverageMap();
                break;
            case 'radar3d':
                this.update3DRadar();
                break;
        }
    }

    // Map Initialization
    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);
        
        // Dark tile layer
        L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_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);
        
        // Map controls
        document.getElementById('center-map').addEventListener('click', () => this.centerMapOnAircraft());
        document.getElementById('reset-map').addEventListener('click', () => this.resetMap());
        document.getElementById('toggle-trails').addEventListener('click', () => this.toggleTrails());
        document.getElementById('toggle-range').addEventListener('click', () => this.toggleRangeCircles());
        document.getElementById('toggle-sources').addEventListener('click', () => this.toggleSources());
        
        // If we already have aircraft data waiting, update markers now that map is ready
        if (this.aircraftData.size > 0) {
            this.updateMapMarkers();
        }
    }

    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);
            
            L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
                attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            }).addTo(this.coverageMap);
        }
        
        // Update coverage controls
        this.updateCoverageControls();
        
        // Coverage controls
        document.getElementById('toggle-heatmap').addEventListener('click', () => this.toggleHeatmap());
        document.getElementById('coverage-source').addEventListener('change', (e) => {
            this.selectedSource = e.target.value;
            this.updateCoverageDisplay();
        });
    }

    // WebSocket Connection
    async initializeWebSocket() {
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${protocol}//${window.location.host}/ws`;
        
        try {
            this.websocket = new WebSocket(wsUrl);
            
            this.websocket.onopen = () => {
                console.log('WebSocket connected');
                this.updateConnectionStatus('connected');
            };
            
            this.websocket.onclose = () => {
                console.log('WebSocket disconnected');
                this.updateConnectionStatus('disconnected');
                // Reconnect after 5 seconds
                setTimeout(() => this.initializeWebSocket(), 5000);
            };
            
            this.websocket.onerror = (error) => {
                console.error('WebSocket error:', error);
                this.updateConnectionStatus('disconnected');
            };
            
            this.websocket.onmessage = (event) => {
                try {
                    const message = JSON.parse(event.data);
                    this.handleWebSocketMessage(message);
                } catch (error) {
                    console.error('Failed to parse WebSocket message:', error);
                }
            };
            
        } catch (error) {
            console.error('WebSocket connection failed:', error);
            this.updateConnectionStatus('disconnected');
        }
    }

    handleWebSocketMessage(message) {
        switch (message.type) {
            case 'initial_data':
            case 'aircraft_update':
                this.updateData(message.data);
                break;
            default:
                console.log('Unknown message type:', message.type);
        }
    }

    updateData(data) {
        // Update aircraft data
        if (data.aircraft) {
            this.aircraftData.clear();
            for (const [icao, aircraft] of Object.entries(data.aircraft)) {
                this.aircraftData.set(icao, aircraft);
            }
        }
        
        // Update sources data
        if (data.sources) {
            this.sourcesData.clear();
            data.sources.forEach(source => {
                this.sourcesData.set(source.id, source);
            });
        }
        
        // Update statistics
        if (data.stats) {
            this.stats = data.stats;
        }
        
        this.lastUpdateTime = new Date();
        
        // Update UI
        this.updateMapMarkers();
        this.updateAircraftTable();
        this.updateStatistics();
        this.updateHeaderInfo();
        
        if (this.currentView === 'radar3d-view') {
            this.update3DRadar();
        }
    }

    // Map Updates
    updateMapMarkers() {
        // Check if map is initialized
        if (!this.map) {
            return;
        }
        
        // Clear stale aircraft markers
        const currentICAOs = new Set(this.aircraftData.keys());
        for (const [icao, marker] of this.aircraftMarkers) {
            if (!currentICAOs.has(icao)) {
                this.map.removeLayer(marker);
                this.aircraftMarkers.delete(icao);
                this.aircraftTrails.delete(icao);
            }
        }
        
        // Update aircraft markers - only for aircraft with valid positions
        // Note: Aircraft without positions are still shown in the table view
        for (const [icao, aircraft] of this.aircraftData) {
            if (aircraft.Latitude && aircraft.Longitude && aircraft.Latitude !== 0 && aircraft.Longitude !== 0) {
                this.updateAircraftMarker(icao, aircraft);
            }
        }
        
        // Update source markers
        if (this.showSources) {
            this.updateSourceMarkers();
        }
        
        // Update range circles
        if (this.showRange) {
            this.updateRangeCircles();
        }
    }

    updateAircraftMarker(icao, aircraft) {
        const pos = [aircraft.Latitude, aircraft.Longitude];
        
        if (this.aircraftMarkers.has(icao)) {
            // Update existing marker
            const marker = this.aircraftMarkers.get(icao);
            marker.setLatLng(pos);
            this.updateMarkerRotation(marker, aircraft.Track || 0);
            this.updatePopupContent(marker, aircraft);
        } else {
            // Create new marker
            const icon = this.createAircraftIcon(aircraft);
            const marker = L.marker(pos, { 
                icon: icon,
                rotationAngle: aircraft.Track || 0
            }).addTo(this.map);
            
            marker.bindPopup(this.createPopupContent(aircraft), {
                maxWidth: 450,
                className: 'aircraft-popup'
            });
            
            this.aircraftMarkers.set(icao, marker);
        }
        
        // Update trails
        if (this.showTrails) {
            this.updateAircraftTrail(icao, pos);
        }
    }

    createAircraftIcon(aircraft) {
        const type = this.getAircraftType(aircraft);
        const color = this.getAircraftColor(type);
        const size = aircraft.OnGround ? 12 : 16;
        
        const svg = `
            <svg width="${size * 2}" height="${size * 2}" viewBox="0 0 32 32">
                <g transform="translate(16,16)">
                    <path d="M0,-12 L-8,8 L-2,8 L0,12 L2,8 L8,8 Z" 
                          fill="${color}" 
                          stroke="#ffffff" 
                          stroke-width="1"
                          filter="drop-shadow(0 0 4px rgba(0,212,255,0.8))"/>
                </g>
            </svg>
        `;
        
        return L.divIcon({
            html: svg,
            iconSize: [size * 2, size * 2],
            iconAnchor: [size, size],
            className: 'aircraft-marker'
        });
    }

    getAircraftType(aircraft) {
        if (aircraft.OnGround) return 'ground';
        if (aircraft.Category) {
            const cat = aircraft.Category.toLowerCase();
            if (cat.includes('military')) return 'military';
            if (cat.includes('cargo') || cat.includes('heavy')) return 'cargo';
            if (cat.includes('light') || cat.includes('glider')) return 'ga';
        }
        if (aircraft.Callsign) {
            const cs = aircraft.Callsign.toLowerCase();
            if (cs.includes('mil') || cs.includes('army') || cs.includes('navy')) return 'military';
            if (cs.includes('cargo') || cs.includes('fedex') || cs.includes('ups')) return 'cargo';
        }
        return 'commercial';
    }

    getAircraftColor(type) {
        const colors = {
            commercial: '#00ff88',
            cargo: '#ff8c00',
            military: '#ff4444',
            ga: '#ffff00',
            ground: '#888888'
        };
        return colors[type] || colors.commercial;
    }

    updateMarkerRotation(marker, track) {
        if (marker._icon) {
            marker._icon.style.transform = `rotate(${track}deg)`;
        }
    }

    updateSourceMarkers() {
        // 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() {
        // 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: 1,
                        opacity: 0.3 - (index * 0.1),
                        dashArray: '5,5'
                    }).addTo(this.map);
                    
                    this.rangeCircles.set(`${id}_${range}`, circle);
                });
            }
        }
    }

    updateAircraftTrail(icao, pos) {
        if (!this.aircraftTrails.has(icao)) {
            this.aircraftTrails.set(icao, []);
        }
        
        const trail = this.aircraftTrails.get(icao);
        trail.push(pos);
        
        // Keep only last 50 positions
        if (trail.length > 50) {
            trail.shift();
        }
        
        // Draw polyline
        const trailLine = L.polyline(trail, {
            color: '#00d4ff',
            weight: 2,
            opacity: 0.6
        }).addTo(this.map);
        
        // Store reference for cleanup
        if (!this.aircraftTrails.get(icao).polyline) {
            this.aircraftTrails.get(icao).polyline = trailLine;
        } else {
            this.map.removeLayer(this.aircraftTrails.get(icao).polyline);
            this.aircraftTrails.get(icao).polyline = trailLine;
        }
    }

    // Popup Content
    createPopupContent(aircraft) {
        const type = this.getAircraftType(aircraft);
        const country = this.getCountryFromICAO(aircraft.ICAO24 || '');
        const flag = this.getCountryFlag(country);
        
        const altitude = aircraft.Altitude || aircraft.BaroAltitude || 0;
        const altitudeM = altitude ? Math.round(altitude * 0.3048) : 0;
        const speedKmh = aircraft.GroundSpeed ? Math.round(aircraft.GroundSpeed * 1.852) : 0;
        const distance = this.calculateDistance(aircraft);
        const distanceKm = distance ? (distance * 1.852).toFixed(1) : 'N/A';
        
        const sources = aircraft.sources ? Object.keys(aircraft.sources).map(id => {
            const source = this.sourcesData.get(id);
            const srcData = aircraft.sources[id];
            return `<span class="source-badge" title="Signal: ${srcData.signal_level?.toFixed(1)} dBFS">
                        ${source?.name || id}
                    </span>`;
        }).join('') : 'N/A';
        
        return `
            <div class="aircraft-popup">
                <div class="popup-header">
                    <div class="flight-info">
                        <span class="icao-flag">${flag}</span>
                        <span class="flight-id">${aircraft.ICAO24 || 'N/A'}</span>
                        ${aircraft.Callsign ? `→ <span class="callsign">${aircraft.Callsign}</span>` : ''}
                    </div>
                </div>
                
                <div class="popup-details">
                    <div class="detail-row">
                        <strong>Country:</strong> ${country}
                    </div>
                    <div class="detail-row">
                        <strong>Type:</strong> ${type.charAt(0).toUpperCase() + type.slice(1)}
                    </div>
                    
                    <div class="detail-grid">
                        <div class="detail-item">
                            <div class="label">Altitude:</div>
                            <div class="value">${altitude ? `${altitude} ft | ${altitudeM} m` : 'N/A'}</div>
                        </div>
                        <div class="detail-item">
                            <div class="label">Squawk:</div>
                            <div class="value">${aircraft.Squawk || 'N/A'}</div>
                        </div>
                        <div class="detail-item">
                            <div class="label">Speed:</div>
                            <div class="value">${aircraft.GroundSpeed ? `${aircraft.GroundSpeed} kt | ${speedKmh} km/h` : 'N/A'}</div>
                        </div>
                        <div class="detail-item">
                            <div class="label">Track:</div>
                            <div class="value">${aircraft.Track ? `${aircraft.Track}°` : 'N/A'}</div>
                        </div>
                        <div class="detail-item">
                            <div class="label">V/Rate:</div>
                            <div class="value">${aircraft.VerticalRate ? `${aircraft.VerticalRate} ft/min` : 'N/A'}</div>
                        </div>
                        <div class="detail-item">
                            <div class="label">Distance:</div>
                            <div class="value">${distanceKm} km</div>
                        </div>
                    </div>
                    
                    <div class="sources-info">
                        <strong>Sources:</strong><br>
                        ${sources}
                    </div>
                    
                    <div class="detail-row">
                        <strong>Position:</strong> ${aircraft.Latitude?.toFixed(4)}°, ${aircraft.Longitude?.toFixed(4)}°
                    </div>
                    <div class="detail-row">
                        <strong>Messages:</strong> ${aircraft.TotalMessages || 0}
                    </div>
                    <div class="detail-row">
                        <strong>Age:</strong> ${aircraft.Age ? aircraft.Age.toFixed(1) : '0'}s
                    </div>
                </div>
            </div>
        `;
    }

    updatePopupContent(marker, aircraft) {
        if (marker && marker.isPopupOpen()) {
            const newContent = this.createPopupContent(aircraft);
            marker.setPopupContent(newContent);
        }
    }

    createSourcePopupContent(source) {
        const aircraftCount = Array.from(this.aircraftData.values())
            .filter(aircraft => aircraft.sources && aircraft.sources[source.id]).length;
        
        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');
        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);
        }
    }

    // Table Management
    updateAircraftTable() {
        // Note: This table shows ALL aircraft we're tracking, including those without 
        // position data. Aircraft without positions will show "No position" in the 
        // location column but still provide useful info like callsign, altitude, etc.
        const tbody = document.getElementById('aircraft-tbody');
        tbody.innerHTML = '';
        
        let filteredData = Array.from(this.aircraftData.values());
        
        // Apply filters
        const searchTerm = document.getElementById('search-input').value.toLowerCase();
        const sourceFilter = document.getElementById('source-filter').value;
        
        if (searchTerm) {
            filteredData = filteredData.filter(aircraft =>
                (aircraft.Callsign && aircraft.Callsign.toLowerCase().includes(searchTerm)) ||
                (aircraft.ICAO24 && aircraft.ICAO24.toLowerCase().includes(searchTerm)) ||
                (aircraft.Squawk && aircraft.Squawk.includes(searchTerm))
            );
        }
        
        if (sourceFilter) {
            filteredData = filteredData.filter(aircraft =>
                aircraft.sources && aircraft.sources[sourceFilter]
            );
        }
        
        // Sort data
        const sortBy = document.getElementById('sort-select').value;
        this.sortAircraft(filteredData, sortBy);
        
        // Populate table
        filteredData.forEach(aircraft => {
            const row = this.createTableRow(aircraft);
            tbody.appendChild(row);
        });
        
        // Update source filter options
        this.updateSourceFilter();
    }

    createTableRow(aircraft) {
        const type = this.getAircraftType(aircraft);
        // ICAO24 is already a hex string from the server
        const icao = aircraft.ICAO24 || 'N/A';
        const altitude = aircraft.Altitude || aircraft.BaroAltitude || 0;
        const distance = this.calculateDistance(aircraft);
        const sources = aircraft.sources ? Object.keys(aircraft.sources).length : 0;
        const bestSignal = this.getBestSignalFromSources(aircraft.sources);
        
        const row = document.createElement('tr');
        row.innerHTML = `
            <td><span class="type-badge ${type}">${icao}</span></td>
            <td>${aircraft.Callsign || '-'}</td>
            <td>${aircraft.Squawk || '-'}</td>
            <td>${altitude ? `${altitude} ft` : '-'}</td>
            <td>${aircraft.GroundSpeed || '-'} kt</td>
            <td>${distance ? distance.toFixed(1) : '-'} km</td>
            <td>${aircraft.Track || '-'}°</td>
            <td>${sources}</td>
            <td><span class="${this.getSignalClass(bestSignal)}">${bestSignal ? bestSignal.toFixed(1) : '-'}</span></td>
            <td>${aircraft.Age ? aircraft.Age.toFixed(0) : '0'}s</td>
        `;
        
        row.addEventListener('click', () => {
            if (aircraft.Latitude && aircraft.Longitude) {
                this.switchView('map');
                this.map.setView([aircraft.Latitude, aircraft.Longitude], 12);
                const marker = this.aircraftMarkers.get(icao);
                if (marker) {
                    marker.openPopup();
                }
            }
        });
        
        return row;
    }

    getBestSignalFromSources(sources) {
        if (!sources) return null;
        let bestSignal = -999;
        for (const [id, data] of Object.entries(sources)) {
            if (data.signal_level > bestSignal) {
                bestSignal = data.signal_level;
            }
        }
        return bestSignal === -999 ? null : bestSignal;
    }

    getSignalClass(signal) {
        if (!signal) return '';
        if (signal > -10) return 'signal-strong';
        if (signal > -20) return 'signal-good';
        if (signal > -30) return 'signal-weak';
        return 'signal-poor';
    }

    updateSourceFilter() {
        const select = document.getElementById('source-filter');
        const currentValue = select.value;
        
        // Clear options except "All Sources"
        select.innerHTML = '<option value="">All Sources</option>';
        
        // Add source options
        for (const [id, source] of this.sourcesData) {
            const option = document.createElement('option');
            option.value = id;
            option.textContent = source.name;
            if (id === currentValue) option.selected = true;
            select.appendChild(option);
        }
    }

    sortAircraft(aircraft, sortBy) {
        aircraft.sort((a, b) => {
            switch (sortBy) {
                case 'distance':
                    return (this.calculateDistance(a) || Infinity) - (this.calculateDistance(b) || Infinity);
                case 'altitude':
                    return (b.Altitude || b.BaroAltitude || 0) - (a.Altitude || a.BaroAltitude || 0);
                case 'speed':
                    return (b.GroundSpeed || 0) - (a.GroundSpeed || 0);
                case 'flight':
                    return (a.Callsign || a.ICAO24 || '').localeCompare(b.Callsign || b.ICAO24 || '');
                case 'icao':
                    return (a.ICAO24 || '').localeCompare(b.ICAO24 || '');
                case 'squawk':
                    return (a.Squawk || '').localeCompare(b.Squawk || '');
                case 'signal':
                    return (this.getBestSignalFromSources(b.sources) || -999) - (this.getBestSignalFromSources(a.sources) || -999);
                case 'age':
                    return (a.Age || 0) - (b.Age || 0);
                default:
                    return 0;
            }
        });
    }

    // Statistics
    updateStatistics() {
        document.getElementById('total-aircraft').textContent = this.aircraftData.size;
        document.getElementById('active-sources').textContent = 
            Array.from(this.sourcesData.values()).filter(s => s.active).length;
        
        // Calculate max range
        let maxDistance = 0;
        for (const aircraft of this.aircraftData.values()) {
            const distance = this.calculateDistance(aircraft);
            if (distance && distance > maxDistance) {
                maxDistance = distance;
            }
        }
        document.getElementById('max-range').textContent = `${maxDistance.toFixed(1)} km`;
        
        // Update message rate
        const totalMessages = this.stats.total_messages || 0;
        document.getElementById('messages-sec').textContent = Math.round(totalMessages / 60);
        
        this.updateCharts();
    }

    updateHeaderInfo() {
        document.getElementById('aircraft-count').textContent = `${this.aircraftData.size} aircraft`;
        document.getElementById('sources-count').textContent = `${this.sourcesData.size} sources`;
        
        this.updateClocks();
    }

    // Event Listeners
    initializeEventListeners() {
        document.getElementById('search-input').addEventListener('input', () => this.updateAircraftTable());
        document.getElementById('sort-select').addEventListener('change', () => this.updateAircraftTable());
        document.getElementById('source-filter').addEventListener('change', () => this.updateAircraftTable());
    }

    // Map Controls
    centerMapOnAircraft() {
        if (this.aircraftData.size === 0) return;
        
        const validAircraft = Array.from(this.aircraftData.values())
            .filter(a => a.Latitude && a.Longitude);
        
        if (validAircraft.length === 0) return;
        
        if (validAircraft.length === 1) {
            // Center on single aircraft
            const aircraft = validAircraft[0];
            this.map.setView([aircraft.Latitude, aircraft.Longitude], 12);
        } else {
            // Fit bounds to all aircraft
            const bounds = L.latLngBounds(
                validAircraft.map(a => [a.Latitude, a.Longitude])
            );
            this.map.fitBounds(bounds.pad(0.1));
        }
    }

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

    toggleTrails() {
        this.showTrails = !this.showTrails;
        document.getElementById('toggle-trails').textContent = 
            this.showTrails ? 'Hide Trails' : 'Show Trails';
        
        if (!this.showTrails) {
            // Clear all trails
            this.aircraftTrails.forEach((trail, icao) => {
                if (trail.polyline) {
                    this.map.removeLayer(trail.polyline);
                }
            });
            this.aircraftTrails.clear();
        }
    }

    toggleRangeCircles() {
        this.showRange = !this.showRange;
        document.getElementById('toggle-range').textContent = 
            this.showRange ? 'Hide Range' : 'Show Range';
        
        if (this.showRange) {
            this.updateRangeCircles();
        } else {
            this.rangeCircles.forEach(circle => this.map.removeLayer(circle));
            this.rangeCircles.clear();
        }
    }

    toggleSources() {
        this.showSources = !this.showSources;
        document.getElementById('toggle-sources').textContent = 
            this.showSources ? 'Hide Sources' : 'Show Sources';
        
        if (this.showSources) {
            this.updateSourceMarkers();
        } else {
            this.sourceMarkers.forEach(marker => this.map.removeLayer(marker));
            this.sourceMarkers.clear();
        }
    }

    // Coverage and Heatmap
    updateCoverageControls() {
        const select = document.getElementById('coverage-source');
        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) 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;
        }
        
        if (this.heatmapLayer) {
            this.coverageMap.removeLayer(this.heatmapLayer);
            this.heatmapLayer = null;
            document.getElementById('toggle-heatmap').textContent = 'Show Heatmap';
        } else {
            try {
                const response = await fetch(`/api/heatmap/${this.selectedSource}`);
                const data = await response.json();
                
                // Create heatmap layer (simplified)
                // In a real implementation, you'd use a proper heatmap library
                this.createHeatmapOverlay(data);
                document.getElementById('toggle-heatmap').textContent = 'Hide Heatmap';
                
            } catch (error) {
                console.error('Failed to load heatmap data:', error);
            }
        }
    }

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

    // Charts (continued in next part due to length)
    initializeCharts() {
        this.charts.aircraft = new Chart(document.getElementById('aircraft-chart'), {
            type: 'line',
            data: {
                labels: [],
                datasets: [{
                    label: 'Aircraft Count',
                    data: [],
                    borderColor: '#00d4ff',
                    backgroundColor: 'rgba(0, 212, 255, 0.1)',
                    tension: 0.4
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: { display: false }
                },
                scales: {
                    x: { display: false },
                    y: { 
                        beginAtZero: true,
                        ticks: { color: '#888' }
                    }
                }
            }
        });
        
        // Add other charts...
    }

    updateCharts() {
        const now = new Date();
        const timeLabel = now.toLocaleTimeString();
        
        // Update aircraft count chart
        if (this.charts.aircraft) {
            const chart = this.charts.aircraft;
            chart.data.labels.push(timeLabel);
            chart.data.datasets[0].data.push(this.aircraftData.size);
            
            if (chart.data.labels.length > 20) {
                chart.data.labels.shift();
                chart.data.datasets[0].data.shift();
            }
            
            chart.update('none');
        }
    }

    // 3D Radar (basic implementation)
    initialize3DRadar() {
        try {
            const container = document.getElementById('radar3d-container');
            if (!container) return;
            
            // Create scene
            this.radar3d = {
                scene: new THREE.Scene(),
                camera: new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000),
                renderer: new THREE.WebGLRenderer({ alpha: true, antialias: true }),
                controls: null,
                aircraftMeshes: new Map()
            };
            
            // Set up renderer
            this.radar3d.renderer.setSize(container.clientWidth, container.clientHeight);
            this.radar3d.renderer.setClearColor(0x0a0a0a, 0.9);
            container.appendChild(this.radar3d.renderer.domElement);
            
            // Add lighting
            const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
            this.radar3d.scene.add(ambientLight);
            
            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
            directionalLight.position.set(10, 10, 5);
            this.radar3d.scene.add(directionalLight);
            
            // Set up camera
            this.radar3d.camera.position.set(0, 50, 50);
            this.radar3d.camera.lookAt(0, 0, 0);
            
            // Add controls
            this.radar3d.controls = new OrbitControls(this.radar3d.camera, this.radar3d.renderer.domElement);
            this.radar3d.controls.enableDamping = true;
            this.radar3d.controls.dampingFactor = 0.05;
            
            // Add ground plane
            const groundGeometry = new THREE.PlaneGeometry(200, 200);
            const groundMaterial = new THREE.MeshLambertMaterial({ 
                color: 0x2a4d3a, 
                transparent: true, 
                opacity: 0.5 
            });
            const ground = new THREE.Mesh(groundGeometry, groundMaterial);
            ground.rotation.x = -Math.PI / 2;
            this.radar3d.scene.add(ground);
            
            // Add grid
            const gridHelper = new THREE.GridHelper(200, 20, 0x44aa44, 0x44aa44);
            this.radar3d.scene.add(gridHelper);
            
            // Start render loop
            this.render3DRadar();
            
            console.log('3D Radar initialized successfully');
        } catch (error) {
            console.error('Failed to initialize 3D radar:', error);
        }
    }

    update3DRadar() {
        if (!this.radar3d || !this.radar3d.scene) return;
        
        try {
            // Update aircraft positions in 3D space
            this.aircraftData.forEach((aircraft, icao) => {
                if (aircraft.Latitude && aircraft.Longitude) {
                    const key = icao.toString();
                    
                    if (!this.radar3d.aircraftMeshes.has(key)) {
                        // Create new aircraft mesh
                        const geometry = new THREE.ConeGeometry(0.5, 2, 6);
                        const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
                        const mesh = new THREE.Mesh(geometry, material);
                        this.radar3d.aircraftMeshes.set(key, mesh);
                        this.radar3d.scene.add(mesh);
                    }
                    
                    const mesh = this.radar3d.aircraftMeshes.get(key);
                    
                    // Convert lat/lon to local coordinates (simplified)
                    const x = (aircraft.Longitude - (-0.4600)) * 111320 * Math.cos(aircraft.Latitude * Math.PI / 180) / 1000;
                    const z = -(aircraft.Latitude - 51.4700) * 111320 / 1000;
                    const y = (aircraft.Altitude || 0) / 1000; // Convert feet to km for display
                    
                    mesh.position.set(x, y, z);
                    
                    // Orient mesh based on track
                    if (aircraft.Track !== undefined) {
                        mesh.rotation.y = -aircraft.Track * Math.PI / 180;
                    }
                }
            });
            
            // Remove old aircraft
            this.radar3d.aircraftMeshes.forEach((mesh, key) => {
                if (!this.aircraftData.has(parseInt(key, 16))) {
                    this.radar3d.scene.remove(mesh);
                    this.radar3d.aircraftMeshes.delete(key);
                }
            });
        } catch (error) {
            console.error('Failed to update 3D radar:', error);
        }
    }

    render3DRadar() {
        if (!this.radar3d) return;
        
        requestAnimationFrame(() => this.render3DRadar());
        
        if (this.radar3d.controls) {
            this.radar3d.controls.update();
        }
        
        this.radar3d.renderer.render(this.radar3d.scene, this.radar3d.camera);
    }

    // Utility functions
    updateConnectionStatus(status) {
        const statusEl = document.getElementById('connection-status');
        statusEl.className = `connection-status ${status}`;
        statusEl.textContent = status === 'connected' ? 'Connected' : 'Disconnected';
    }

    initializeClocks() {
        this.updateClocks();
    }

    updateClocks() {
        const now = new Date();
        const utcNow = new Date(now.getTime() + (now.getTimezoneOffset() * 60000));
        
        this.updateClock('utc', utcNow);
        this.updateClock('update', this.lastUpdateTime);
    }

    updateClock(prefix, time) {
        const hours = time.getUTCHours();
        const minutes = time.getUTCMinutes();
        
        const hourAngle = (hours % 12) * 30 + minutes * 0.5;
        const minuteAngle = minutes * 6;
        
        const hourHand = document.getElementById(`${prefix}-hour`);
        const minuteHand = document.getElementById(`${prefix}-minute`);
        
        if (hourHand) hourHand.style.transform = `rotate(${hourAngle}deg)`;
        if (minuteHand) minuteHand.style.transform = `rotate(${minuteAngle}deg)`;
    }

    calculateDistance(aircraft) {
        if (!aircraft.Latitude || !aircraft.Longitude) return null;
        
        // Use closest source as reference point
        let minDistance = Infinity;
        for (const [id, srcData] of Object.entries(aircraft.sources || {})) {
            if (srcData.distance && srcData.distance < minDistance) {
                minDistance = srcData.distance;
            }
        }
        
        return minDistance === Infinity ? null : minDistance;
    }

    getCountryFromICAO(icao) {
        if (!icao || icao.length < 6) return 'Unknown';
        
        const prefix = icao[0];
        const countryMap = {
            '4': 'Europe',
            'A': 'United States',
            'C': 'Canada', 
            'D': 'Germany',
            'F': 'France',
            'G': 'United Kingdom',
            'I': 'Italy',
            'J': 'Japan'
        };
        
        return countryMap[prefix] || 'Unknown';
    }

    getCountryFlag(country) {
        const flags = {
            'United States': '🇺🇸',
            'Canada': '🇨🇦',
            'Germany': '🇩🇪',
            'France': '🇫🇷',
            'United Kingdom': '🇬🇧',
            'Italy': '🇮🇹',
            'Japan': '🇯🇵',
            'Europe': '🇪🇺'
        };
        return flags[country] || '🏳️';
    }

    startPeriodicTasks() {
        // Update clocks every second
        setInterval(() => this.updateClocks(), 1000);
        
        // Periodic cleanup
        setInterval(() => {
            // Clean up old trail data, etc.
        }, 30000);
    }

    showError(message) {
        console.error(message);
        // Could implement toast notifications here
    }
}

// Initialize application when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
    window.skyview = new SkyView();
});