// TM GNSS Guard - Dashboard JavaScript
// Auto-refreshes data every 10 seconds and updates the UI

let map = null;
let markers = {};
let currentData = null;
let lastFetchSucceeded = false;
let lastValidationTimestamp = null;

// Route visualization
let routeMarkers = [];
let routeCoords = [];  // Store route coordinates for bounds calculation
let showRouteEnabled = getRoutePreference();  // Load from localStorage
let isInitialMapLoad = true;  // Only fit bounds on initial load

// Get route preference from localStorage (defaults to true if not set)
function getRoutePreference() {
    if (!window.SHOW_ROUTE) return false;
    const stored = localStorage.getItem('showRoute');
    return stored === null ? true : stored === 'true';
}

// Save route preference to localStorage
function saveRoutePreference(enabled) {
    localStorage.setItem('showRoute', enabled ? 'true' : 'false');
}

// =============================================================================
// AUTO-REFRESH PAGE (every 1 hour to pick up deployments)
// =============================================================================
const PAGE_LOAD_TIME = Date.now();
const AUTO_REFRESH_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
let lastVisibilityCheck = Date.now();

function checkAutoRefresh() {
    const elapsed = Date.now() - PAGE_LOAD_TIME;
    if (elapsed >= AUTO_REFRESH_INTERVAL_MS) {
        console.log('Auto-refreshing page after 1 hour...');
        window.location.reload();
    }
}

// Check for refresh on visibility change (tab becomes active)
document.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'visible') {
        const now = Date.now();
        // Only check if at least 10 seconds since last check (prevents rapid refreshes)
        if (now - lastVisibilityCheck > 10000) {
            lastVisibilityCheck = now;
            checkAutoRefresh();
        }
    }
});

// Periodic check every 5 minutes while tab is active
setInterval(checkAutoRefresh, 5 * 60 * 1000);

// Initialize map
function initMap() {
    // Create map centered on default location
    map = L.map('map', {
        zoomControl: true
    }).setView([34.665151, 33.016326], 11);
    
    // Dark basemap
    L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
        maxZoom: 19,
        attribution: '&copy; OpenStreetMap & CARTO'
    }).addTo(map);
    
    // Recalculate marker offsets when zoom changes
    map.on('zoomend', () => {
        if (currentData) {
            updateMap(currentData);
        }
    });
}

// Create marker icons (using local files)
function makeIcon(color) {
    return new L.Icon({
        iconUrl: `/static/markers/marker-icon-${color}.png`,
        shadowUrl: '/static/markers/marker-shadow.png',
        iconSize: [25, 41],
        iconAnchor: [12, 41],
        popupAnchor: [1, -34]
    });
}

const iconPrimary = makeIcon('violet');
const iconPrimaryAlert = makeIcon('red');
const iconAIS = makeIcon('blue');
const iconStarlinkGps = makeIcon('yellow');
const iconStarlinkLocation = makeIcon('green');
const iconSecondary = makeIcon('grey');

// Format timestamp as relative time
function formatRelativeTime(timestampUnix) {
    if (!timestampUnix) return '-';
    
    const now = Date.now() / 1000;
    const diff = now - timestampUnix;
    
    if (diff < 0) return 'just now';
    if (diff < 60) return `${Math.floor(diff)} sec ago`;
    if (diff < 3600) return `${Math.floor(diff / 60)} min ago`;
    if (diff < 86400) return `${Math.floor(diff / 3600)} hr ago`;
    return `${Math.floor(diff / 86400)} days ago`;
}

// Format UTC timestamp for display
function formatUTCTimestamp(isoString) {
    if (!isoString) return '-';
    
    const date = new Date(isoString);
    const day = String(date.getUTCDate()).padStart(2, '0');
    const month = String(date.getUTCMonth() + 1).padStart(2, '0');
    const year = date.getUTCFullYear();
    const hours = String(date.getUTCHours()).padStart(2, '0');
    const minutes = String(date.getUTCMinutes()).padStart(2, '0');
    const seconds = String(date.getUTCSeconds()).padStart(2, '0');
    
    return `${day}/${month}/${year} ${hours}:${minutes}:${seconds}`;
}

// Log event to event log
function logEvent(level, text) {
    const eventLog = document.getElementById('eventLog');
    if (!eventLog) return;
    
    const div = document.createElement('div');
    div.className = 'event level-' + level;
    const spanLevel = document.createElement('span');
    spanLevel.className = 'level';
    spanLevel.textContent = level.toUpperCase();
    div.appendChild(spanLevel);
    const spanText = document.createElement('span');
    const timestamp = new Date().toTimeString().slice(0, 8);
    spanText.textContent = ' [' + timestamp + '] ' + text;
    div.appendChild(spanText);
    eventLog.appendChild(div);
    
    // Limit to last 3 events (re-query each iteration since querySelectorAll is static)
    while (eventLog.querySelectorAll('.event').length > 3) {
        const firstEvent = eventLog.querySelector('.event');
        if (firstEvent) {
            eventLog.removeChild(firstEvent);
        } else {
            break;
        }
    }
}

// Update source card
function updateSource(sourceName, sourceData) {
    const card = document.getElementById(`card-${sourceName}`);
    const badge = document.getElementById(`badge-${sourceName}`);
    const coordsEl = document.getElementById(`coords-${sourceName}`);
    const updateEl = document.getElementById(`update-${sourceName}`);
    
    if (!card || !badge) return;
    
    // Reset card classes
    card.classList.remove('ok', 'warn', 'crit', 'stale', 'offline');
    badge.className = 'badge';
    
    if (!sourceData.enabled) {
        // Not configured
        card.classList.add('offline');
        badge.classList.add('badge-offline');
        badge.textContent = 'NOT CONFIGURED';
        if (coordsEl) {
            coordsEl.textContent = 'No data source configured.';
        }
        if (updateEl) {
            updateEl.textContent = '-';
            updateEl.className = '';
        }
    } else if (sourceData.status === 'missing') {
        // Missing data
        card.classList.add('crit');
        badge.classList.add('badge-danger');
        badge.textContent = 'MISSING';
        if (coordsEl) {
            coordsEl.textContent = 'MISSING';
            coordsEl.className = 'alert';
        }
        if (updateEl) {
            updateEl.textContent = formatRelativeTime(sourceData.last_update_unix);
            updateEl.className = 'alert';
        }
    } else if (sourceData.status === 'stale' || sourceData.is_stale) {
        // Stale data - has coordinates but timestamp is old
        card.classList.add('stale');
        badge.classList.add('badge-stale');
        badge.textContent = 'STALE';
        
        if (coordsEl && sourceData.coordinates) {
            const lat = sourceData.coordinates.latitude;
            const lon = sourceData.coordinates.longitude;
            coordsEl.textContent = `${lat.toFixed(6)}, ${lon.toFixed(6)}`;
            coordsEl.className = '';
        }
        if (updateEl) {
            updateEl.textContent = formatRelativeTime(sourceData.last_update_unix);
            updateEl.className = 'stale-text';
        }
    } else {
        // Has valid data
        card.classList.add('ok');
        badge.classList.add('badge-healthy');
        badge.textContent = 'HEALTHY';
        
        if (coordsEl && sourceData.coordinates) {
            const lat = sourceData.coordinates.latitude;
            const lon = sourceData.coordinates.longitude;
            coordsEl.textContent = `${lat.toFixed(6)}, ${lon.toFixed(6)}`;
            coordsEl.className = '';
        }
        if (updateEl) {
            updateEl.textContent = formatRelativeTime(sourceData.last_update_unix);
            updateEl.className = '';
        }
    }
}

// Calculate offset for markers to spread them in a circle when close together
function calculateMarkerOffsets(sourceCoords, zoomLevel) {
    if (Object.keys(sourceCoords).length <= 1) {
        // Single marker, no offset needed
        const result = {};
        for (const [name, coord] of Object.entries(sourceCoords)) {
            result[name] = { lat: coord.lat, lon: coord.lon, offsetLat: 0, offsetLon: 0 };
        }
        return result;
    }
    
    // Calculate centroid
    let sumLat = 0, sumLon = 0, count = 0;
    for (const coord of Object.values(sourceCoords)) {
        sumLat += coord.lat;
        sumLon += coord.lon;
        count++;
    }
    const centroidLat = sumLat / count;
    const centroidLon = sumLon / count;
    
    // Check if markers are close together (within ~50 meters)
    const closeThreshold = 0.0005; // ~50m in degrees
    let maxDist = 0;
    for (const coord of Object.values(sourceCoords)) {
        const dist = Math.sqrt(
            Math.pow(coord.lat - centroidLat, 2) + 
            Math.pow(coord.lon - centroidLon, 2)
        );
        maxDist = Math.max(maxDist, dist);
    }
    
    // If markers are spread out enough, don't offset
    if (maxDist > closeThreshold) {
        const result = {};
        for (const [name, coord] of Object.entries(sourceCoords)) {
            result[name] = { lat: coord.lat, lon: coord.lon, offsetLat: 0, offsetLon: 0 };
        }
        return result;
    }
    
    // Calculate offset radius based on zoom level (smaller offset when zoomed in)
    // At zoom 15, offset ~30m; at zoom 10, offset ~100m
    const baseOffset = 0.0003; // ~30m base offset
    const zoomFactor = Math.pow(2, 15 - Math.min(zoomLevel, 18));
    const offsetRadius = baseOffset * zoomFactor;
    
    // Arrange markers in a circle around centroid
    const result = {};
    const sourceNames = Object.keys(sourceCoords);
    const angleStep = (2 * Math.PI) / sourceNames.length;
    
    sourceNames.forEach((name, index) => {
        const angle = angleStep * index - Math.PI / 2; // Start from top
        const offsetLat = offsetRadius * Math.cos(angle);
        const offsetLon = offsetRadius * Math.sin(angle) * 1.5; // Adjust for latitude distortion
        
        result[name] = {
            lat: centroidLat + offsetLat,
            lon: centroidLon + offsetLon,
            offsetLat: offsetLat,
            offsetLon: offsetLon,
            originalLat: sourceCoords[name].lat,
            originalLon: sourceCoords[name].lon
        };
    });
    
    return result;
}

// Update map markers
function updateMap(data) {
    if (!data.map_center) return;
    
    const sourceMapping = {
        'nmea_primary': { icon: iconPrimary, name: 'Primary GPS' },
        'nmea_secondary': { icon: iconSecondary, name: 'Secondary GPS' },
        'tm_ais': { icon: iconAIS, name: 'TM AIS GPS' },
        'starlink_gps': { icon: iconStarlinkGps, name: 'Starlink GPS' },
        'starlink_location': { icon: iconStarlinkLocation, name: 'Starlink Location' }
    };
    
    // Collect all valid source coordinates
    const sourceCoords = {};
    const allCoords = [];
    
    Object.keys(sourceMapping).forEach(sourceName => {
        const sourceData = data.sources[sourceName];
        if (sourceData && sourceData.enabled && sourceData.status !== 'missing' && sourceData.coordinates) {
            const lat = sourceData.coordinates.latitude;
            const lon = sourceData.coordinates.longitude;
            sourceCoords[sourceName] = { lat, lon };
            allCoords.push([lat, lon]);
        }
    });
    
    // Calculate offsets for overlapping markers
    const zoomLevel = map.getZoom() || 13;
    const offsetPositions = calculateMarkerOffsets(sourceCoords, zoomLevel);
    
    // Update or create markers for each source
    Object.keys(sourceMapping).forEach(sourceName => {
        const sourceData = data.sources[sourceName];
        if (!sourceData || !sourceData.enabled || sourceData.status === 'missing' || !sourceData.coordinates) {
            // Remove marker if it exists
            if (markers[sourceName]) {
                map.removeLayer(markers[sourceName]);
                delete markers[sourceName];
            }
            return;
        }
        
        const mapping = sourceMapping[sourceName];
        const position = offsetPositions[sourceName];
        
        // Use alert icon for primary if there's an alert
        let icon = mapping.icon;
        if (sourceName === 'nmea_primary' && data.has_alert && !data.is_valid) {
            icon = iconPrimaryAlert;
        }
        
        // Build popup with original coordinates
        const origLat = sourceData.coordinates.latitude;
        const origLon = sourceData.coordinates.longitude;
        const popupContent = `<b>${mapping.name}</b><br>` +
            `Lat: ${origLat.toFixed(6)}<br>` +
            `Lon: ${origLon.toFixed(6)}`;
        
        if (markers[sourceName]) {
            markers[sourceName].setLatLng([position.lat, position.lon]).setIcon(icon);
            markers[sourceName].setPopupContent(popupContent);
        } else {
            markers[sourceName] = L.marker([position.lat, position.lon], { icon: icon })
                .addTo(map)
                .bindPopup(popupContent);
        }
    });
    
    // Fit map to show all markers (only on initial load, not on refresh)
    // If route is enabled, wait for route data to load before fitting bounds
    if (isInitialMapLoad && !window.SHOW_ROUTE) {
        if (allCoords.length > 0) {
            const bounds = L.latLngBounds(allCoords);
            map.fitBounds(bounds, {
                padding: [50, 50],
                maxZoom: 15
            });
        } else if (data.map_center && data.map_center.latitude && data.map_center.longitude) {
            map.setView([data.map_center.latitude, data.map_center.longitude], 13);
        }
        isInitialMapLoad = false;
    }
}

// Track alarm state
let alarmActive = false;
let alarmAcknowledged = false;

// Update global status pill and border frame
function updateGlobalStatus(data) {
    const statusPill = document.getElementById('globalStatusPill');
    const statusText = statusPill ? statusPill.querySelector('.status-text') : null;
    const borderFrame = document.getElementById('healthBorderFrame');
    
    if (statusPill) {
        statusPill.classList.remove('warn', 'crit', 'alarm-active', 'alarm-acknowledged');
    }
    if (borderFrame) {
        borderFrame.classList.remove('warn', 'crit');
    }
    
    if (data.is_valid) {
        if (statusText) {
            statusText.textContent = 'GNSS Integrity: Stable';
        } else if (statusPill) {
            statusPill.textContent = 'GNSS Integrity: Stable';
        }
        // Border frame hidden (no class) when healthy
        // Reset alarm state when status returns to healthy
        alarmActive = false;
        alarmAcknowledged = false;
    } else if (data.has_alert && data.max_distance_km !== null) {
        if (statusText) {
            statusText.textContent = 'GNSS Integrity: At Risk';
        } else if (statusPill) {
            statusPill.textContent = 'GNSS Integrity: At Risk';
        }
        if (statusPill) {
            statusPill.classList.add('crit');
        }
        if (borderFrame) {
            borderFrame.classList.add('crit');
        }
        // Alarm should be active in this state
        if (!alarmAcknowledged) {
            alarmActive = true;
        }
    } else {
        if (statusText) {
            statusText.textContent = 'GNSS Integrity: Degraded';
        } else if (statusPill) {
            statusPill.textContent = 'GNSS Integrity: Degraded';
        }
        if (statusPill) {
            statusPill.classList.add('warn');
        }
        if (borderFrame) {
            borderFrame.classList.add('warn');
        }
        // Alarm should be active in this state
        if (!alarmAcknowledged) {
            alarmActive = true;
        }
    }
    
    // Update alarm visual state
    updateAlarmVisualState();
}

// Update alarm visual state on the button
function updateAlarmVisualState() {
    const statusPill = document.getElementById('globalStatusPill');
    if (!statusPill) return;
    
    statusPill.classList.remove('alarm-active', 'alarm-acknowledged');
    
    if (alarmActive && !alarmAcknowledged) {
        statusPill.classList.add('alarm-active');
    } else if (alarmAcknowledged) {
        statusPill.classList.add('alarm-acknowledged');
    }
}

// Acknowledge alarm - called when user clicks the status button
async function acknowledgeAlarm() {
    const statusPill = document.getElementById('globalStatusPill');
    
    // Only allow acknowledgment if alarm is active
    if (!alarmActive && !statusPill.classList.contains('warn') && !statusPill.classList.contains('crit')) {
        console.log('No active alarm to acknowledge');
        return;
    }
    
    try {
        const response = await fetch('/api/alarm/acknowledge', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            }
        });
        
        if (response.ok) {
            const data = await response.json();
            console.log('Alarm acknowledged:', data);
            
            alarmAcknowledged = true;
            alarmActive = false;
            updateAlarmVisualState();
            
            logEvent('info', 'Alarm acknowledged - buzzer muted');
        } else {
            console.error('Failed to acknowledge alarm:', response.statusText);
            logEvent('warn', 'Failed to acknowledge alarm');
        }
    } catch (error) {
        console.error('Error acknowledging alarm:', error);
        logEvent('warn', 'Error acknowledging alarm: ' + error.message);
    }
}

// Fetch alarm status from server
async function fetchAlarmStatus() {
    try {
        const response = await fetch('/api/alarm/status');
        if (response.ok) {
            const data = await response.json();
            alarmActive = data.alarm_active;
            alarmAcknowledged = data.alarm_acknowledged;
            updateAlarmVisualState();
        }
    } catch (error) {
        console.error('Error fetching alarm status:', error);
    }
}

// Update alert banner
function updateAlertBanner(data) {
    const banner = document.getElementById('alert-banner');
    const alertText = document.getElementById('alertText');
    const alertDistance = document.getElementById('alert-distance-value');
    const alertIndicator = document.getElementById('alertIndicator');
    
    if (!banner) return;
    
    banner.classList.add('hidden');
    banner.classList.remove('alert-critical', 'alert-warning');
    
    if (data.has_alert && !data.is_valid && data.max_distance_km !== null) {
        // Show distance alert
        banner.classList.remove('hidden');
        banner.classList.add('alert-critical');
        if (alertDistance) {
            alertDistance.textContent = `${data.max_distance_km.toFixed(1)} km`;
        }
        if (alertText) {
            alertText.textContent = `GPS Jamming or Spoofing Alert! Location Distance: ${data.max_distance_km.toFixed(1)} km`;
        }
        if (alertIndicator) {
            alertIndicator.style.background = 'var(--accent-red)';
        }
    } else if (data.has_alert) {
        // Has alert but not distance-based (missing sources)
        banner.classList.remove('hidden');
        banner.classList.add('alert-warning');
        if (alertText) {
            alertText.textContent = 'Some GPS sources are missing or stale.';
        }
        if (alertIndicator) {
            alertIndicator.style.background = 'var(--accent-amber)';
        }
    }
}

// Helper function to show degraded state
function showDegradedState(errorMessage) {
    lastFetchSucceeded = false;
    
    // Update status pill and border frame to degraded FIRST (before logging which could fail)
    try {
        const statusPill = document.getElementById('globalStatusPill');
        const statusText = statusPill ? statusPill.querySelector('.status-text') : null;
        if (statusPill) {
            if (statusText) {
                statusText.textContent = 'GNSS Integrity: Degraded';
            } else {
                statusPill.textContent = 'GNSS Integrity: Degraded';
            }
            statusPill.classList.remove('crit');
            statusPill.classList.add('warn');
            // Activate alarm state
            if (!alarmAcknowledged) {
                alarmActive = true;
                updateAlarmVisualState();
            }
        }
        const borderFrame = document.getElementById('healthBorderFrame');
        if (borderFrame) {
            borderFrame.classList.remove('crit');
            borderFrame.classList.add('warn');
        }
    } catch (e) {
        console.error('Error updating status pill:', e);
    }
    
    // Mark all "Updated" timestamps as stale/error (red)
    try {
        const sources = ['nmea_primary', 'nmea_secondary', 'tm_ais', 'starlink_gps', 'starlink_location'];
        sources.forEach(sourceName => {
            const updateEl = document.getElementById(`update-${sourceName}`);
            if (updateEl) {
                updateEl.classList.add('stale-text');
            }
        });
    } catch (e) {
        console.error('Error updating source timestamps:', e);
    }
    
    // Log the error message last
    logEvent('crit', errorMessage);
}

// Fetch and update data
async function fetchData() {
    try {
        const response = await fetch('/api/status');
        if (!response.ok) {
            console.error('Failed to fetch status:', response.statusText);
            showDegradedState(`Server error: ${response.status} ${response.statusText}`);
            return;
        }
        
        const data = await response.json();
        currentData = data;
        lastFetchSucceeded = true;
        
        // Update all sources
        const sources = ['nmea_primary', 'nmea_secondary', 'tm_ais', 'starlink_gps', 'starlink_location'];
        sources.forEach(sourceName => {
            updateSource(sourceName, data.sources[sourceName]);
        });
        
        // If distance-based alert (GPS jamming/spoofing), mark ALL enabled sources as "AT RISK"
        if (data.has_alert && !data.is_valid && data.max_distance_km !== null) {
            sources.forEach(sourceName => {
                const sourceData = data.sources[sourceName];
                // Only mark sources that have coordinates (participated in distance validation)
                if (sourceData && sourceData.enabled && sourceData.status !== 'missing' && sourceData.coordinates) {
                    const card = document.getElementById(`card-${sourceName}`);
                    const badge = document.getElementById(`badge-${sourceName}`);
                    if (card) {
                        card.classList.remove('ok', 'stale');
                        card.classList.add('crit');
                    }
                    if (badge) {
                        badge.className = 'badge badge-danger';
                        badge.textContent = 'AT RISK';
                    }
                }
            });
        }
        
        // Capture initial load flag before updateMap modifies it
        const wasInitialLoad = isInitialMapLoad;
        
        // Update map
        updateMap(data);
        
        // Update global status
        updateGlobalStatus(data);
        
        // Update alert banner
        updateAlertBanner(data);
        
        // Load route data if enabled (fit bounds on initial load)
        if (window.SHOW_ROUTE && showRouteEnabled) {
            loadRouteData(wasInitialLoad);
        }
        
    } catch (error) {
        console.error('Error fetching data:', error);
        showDegradedState('Failed to fetch status data: ' + error.message);
    }
}

// Update relative times
function updateRelativeTimes() {
    if (!currentData) return;
    
    const sources = ['nmea_primary', 'nmea_secondary', 'tm_ais', 'starlink_gps', 'starlink_location'];
    sources.forEach(sourceName => {
        const sourceData = currentData.sources[sourceName];
        const updateEl = document.getElementById(`update-${sourceName}`);
        
        if (updateEl && sourceData && sourceData.enabled && sourceData.last_update_unix) {
            updateEl.textContent = formatRelativeTime(sourceData.last_update_unix);
        }
    });
}

// Tab switching for mobile
function initTabs() {
    const tabBtns = document.querySelectorAll('.tab-btn');
    const tabContents = document.querySelectorAll('.tab-content');
    
    tabBtns.forEach(btn => {
        btn.addEventListener('click', () => {
            const tabName = btn.dataset.tab;
            
            // Update button states
            tabBtns.forEach(b => b.classList.remove('active'));
            btn.classList.add('active');
            
            // Update content visibility
            tabContents.forEach(content => {
                content.classList.remove('active');
                if (content.id === `tab-${tabName}`) {
                    content.classList.add('active');
                }
            });
            
            // Invalidate map size when switching to map tab
            if (tabName === 'map' && map) {
                setTimeout(() => {
                    map.invalidateSize();
                }, 100);
            }
        });
    });
}

// Initialize on page load
document.addEventListener('DOMContentLoaded', () => {
    // Initialize tabs
    initTabs();
    
    // Initialize map
    initMap();
    
    // Initialize route checkbox from stored preference
    initRouteCheckbox();
    
    // Initial log
    logEvent('info', 'TM GNSS Guard dashboard initialized.');
    
    // Initial data fetch
    fetchData();
    
    // Initial alarm status fetch
    fetchAlarmStatus();
    
    // Update relative times every second
    setInterval(updateRelativeTimes, 1000);
    
    // Fetch data every 10 seconds
    setInterval(fetchData, 10000);
    
    // Fetch alarm status every 5 seconds (more frequent to stay in sync with buzzer)
    setInterval(fetchAlarmStatus, 5000);
    
    // Log data fetch events (only when data actually changed)
    setInterval(() => {
        if (currentData && lastFetchSucceeded) {
            // Only log if validation timestamp changed (new data from backend)
            if (currentData.validation_timestamp !== lastValidationTimestamp) {
                lastValidationTimestamp = currentData.validation_timestamp;
                
                if (currentData.has_alert && !currentData.is_valid && currentData.max_distance_km !== null) {
                    logEvent('crit', `Server reports alert: distance ${currentData.max_distance_km.toFixed(1)} km`);
                } else if (!currentData.is_valid) {
                    logEvent('warn', 'Server reports validation issue.');
                } else {
                    logEvent('info', 'Server status OK.');
                }
            }
        }
    }, 10000);
});

// =============================================================================
// ROUTE VISUALIZATION (24h history)
// =============================================================================

async function loadRouteData(fitBoundsAfter = false) {
    if (!window.SHOW_ROUTE) return;
    
    try {
        const response = await fetch('/api/route');
        if (!response.ok) {
            // If route fetch fails on initial load, still fit bounds to source markers
            if (fitBoundsAfter) {
                fitBoundsToMarkers();
                isInitialMapLoad = false;
            }
            return;
        }
        
        const routeData = await response.json();
        renderRoute(routeData);
        
        // Fit bounds to include route on initial load
        if (fitBoundsAfter) {
            // Collect current source marker coordinates
            const sourceCoords = [];
            Object.values(markers).forEach(marker => {
                const latlng = marker.getLatLng();
                sourceCoords.push([latlng.lat, latlng.lng]);
            });
            
            // Use all route points (full 24h) for bounds calculation
            const routePointCoords = [];
            routeData.forEach(point => {
                if (point.lat && point.lng) {
                    routePointCoords.push([point.lat, point.lng]);
                }
            });
            
            const allCoords = [...sourceCoords, ...routePointCoords];
            if (allCoords.length > 0) {
                const bounds = L.latLngBounds(allCoords);
                map.fitBounds(bounds, {
                    padding: [50, 50],
                    maxZoom: 15
                });
            } else {
                fitBoundsToMarkers();
            }
            isInitialMapLoad = false;
        }
        
    } catch (error) {
        console.error('Error loading route:', error);
        // If route fetch fails on initial load, still fit bounds to source markers
        if (fitBoundsAfter) {
            fitBoundsToMarkers();
            isInitialMapLoad = false;
        }
    }
}

function fitBoundsToMarkers() {
    const sourceCoords = [];
    Object.values(markers).forEach(marker => {
        const latlng = marker.getLatLng();
        sourceCoords.push([latlng.lat, latlng.lng]);
    });
    
    if (sourceCoords.length > 0) {
        const bounds = L.latLngBounds(sourceCoords);
        map.fitBounds(bounds, {
            padding: [50, 50],
            maxZoom: 15
        });
    } else if (currentData && currentData.map_center) {
        map.setView([currentData.map_center.latitude, currentData.map_center.longitude], 13);
    }
}

function renderRoute(routeData) {
    clearRouteMarkers();
    routeCoords = [];  // Reset route coordinates
    
    if (!showRouteEnabled || !routeData || routeData.length === 0) return;
    
    // Create small circle markers for route points
    routeData.forEach(point => {
        if (!point.lat || !point.lng) return;
        
        // Store coordinates for bounds calculation
        routeCoords.push([point.lat, point.lng]);
        
        // Determine color based on status
        let color;
        switch (point.status) {
            case 'alert':
                color = '#c62828';  // Red
                break;
            case 'degraded':
                color = '#ffa726';  // Amber
                break;
            default:
                color = '#1fad3a';  // Green
        }
        
        const marker = L.circleMarker([point.lat, point.lng], {
            radius: 4,
            fillColor: color,
            color: color,
            weight: 1,
            opacity: 0.8,
            fillOpacity: 0.6
        }).addTo(map);
        
        // Add popup with details
        const popupContent = `
            <div class="route-popup">
                <div class="popup-header status-${point.status}">${point.status.toUpperCase()}</div>
                <div class="popup-row"><strong>Time:</strong> ${formatUTCTimestamp(point.timestamp)}</div>
                ${point.sources_missing?.length ? `<div class="popup-row"><strong>Missing:</strong> ${point.sources_missing.join(', ')}</div>` : ''}
                ${point.sources_stale?.length ? `<div class="popup-row"><strong>Stale:</strong> ${point.sources_stale.join(', ')}</div>` : ''}
                ${point.max_distance_m > point.threshold_m ? `<div class="popup-row"><strong>Distance:</strong> ${(point.max_distance_m/1000).toFixed(2)} km</div>` : ''}
            </div>
        `;
        marker.bindPopup(popupContent);
        
        routeMarkers.push(marker);
    });
}

function clearRouteMarkers() {
    routeMarkers.forEach(marker => {
        map.removeLayer(marker);
    });
    routeMarkers = [];
    routeCoords = [];
}

function toggleRoute() {
    const checkbox = document.getElementById('showRoute');
    showRouteEnabled = checkbox ? checkbox.checked : false;
    
    // Persist the preference
    saveRoutePreference(showRouteEnabled);
    
    if (showRouteEnabled) {
        loadRouteData();
    } else {
        clearRouteMarkers();
    }
}

// Initialize route checkbox state from localStorage
function initRouteCheckbox() {
    const checkbox = document.getElementById('showRoute');
    if (checkbox) {
        checkbox.checked = showRouteEnabled;
    }
}
