// =====================================================
// GIS Monitoring Application - Modular Version
// =====================================================

// =====================================================
// Main Application Class
// =====================================================
class GISMonitoringApp {
    constructor() {
        this.map = null;
        this.deckOverlay = null;
        this.dataManager = new DataManager();
        this.layerManager = null;
        this.vesselManager = new VesselManager();
        this.sequentialManager = new SequentialPassageManager();
        this.hexagonManager = new HexagonManager();
        this.contextMenuTarget = null;
        this.visualizationMode = 'grid'; // 'grid' or 'hexagon'
        this.vesselPositions = []; // Store vessel positions for hexagon layer
        this.init();
    }

    init() {
        this.initMap();
        this.bindEvents();
        this.initDateTime();
    }

    initMap() {
        this.map = new maplibregl.Map({
            container: 'mapContainer',
            style: {
                version: 8,
                sources: {
                    'local-tiles': {
                        type: 'raster',
                        tiles: ['/api/tiles/world/{z}/{x}/{y}.webp'],
                        tileSize: 256,
                        attribution: 'Local Tile Server'
                    }
                },
                layers: [{
                    id: 'base-tiles',
                    type: 'raster',
                    source: 'local-tiles',
                    minzoom: 4,
                    maxzoom: 14
                }]
            },
            center: [126.0, 35.0],
            zoom: 6
        });

        this.deckOverlay = new deck.MapboxOverlay({
            layers: [],
            getTooltip: this.getTooltip.bind(this)
        });

        this.map.addControl(this.deckOverlay);
        this.map.on('load', () => this.onMapLoad());

        this.layerManager = new LayerManager(this.deckOverlay);
    }

    onMapLoad() {
        this.refreshData();
        this.setupMapContextMenu();
    }

    setupMapContextMenu() {
        const canvas = this.map.getCanvas();
        canvas.addEventListener('contextmenu', (e) => {
            e.preventDefault();

            const pickInfo = this.deckOverlay._deck.pickObject({
                x: e.offsetX,
                y: e.offsetY,
                radius: 1,
                layerIds: ['haegu-layer', 'area-layer']
            });

            if (pickInfo && pickInfo.object) {
                const layerId = pickInfo.layer.id;
                const type = layerId === 'haegu-layer' ? 'haegu' : 'area';
                const clickEvent = {
                    originalEvent: {
                        clientX: e.clientX,
                        clientY: e.clientY
                    }
                };
                this.showContextMenu(clickEvent, type, pickInfo.object.properties);
            }
        });
    }

    bindEvents() {
        $('#showTracks').change(() => this.toggleTracks());
        $('#showAllTracks').change(() => this.toggleAllTracks());
        $('#showHeatmap').change(() => this.toggleHeatmap());
        $('#gisLayerType').change(() => this.refreshData());
        $('#sortBy, #sortOrder').change(() => this.vesselManager.sortAndRender());

        $(document).on('click', () => $('#contextMenu').hide());

        $('#mapContainer').on('contextmenu', (e) => {
            e.preventDefault();
            return false;
        });

        $('#addToSequential').on('click', () => this.addToSequentialFromContext());
        $('#viewAreaDetails').on('click', () => this.viewAreaDetailsFromContext());
    }

    initDateTime() {
        const now = new Date();
        const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);

        $('#passageStartTime').val(yesterday.toISOString().slice(0, 16));
        $('#passageEndTime').val(now.toISOString().slice(0, 16));
    }

    async refreshData() {
        this.showLoading(true);
        try {
            const timeRange = $('#gisTimeRange').val();
            const layerType = $('#gisLayerType').val();

            const promises = [];

            if (layerType === 'haegu' || layerType === 'both') {
                promises.push(this.dataManager.loadHaeguData(timeRange));
            }

            if (layerType === 'area' || layerType === 'both') {
                promises.push(this.dataManager.loadAreaData(timeRange));
            }

            await Promise.all(promises);

            // Update visualization based on current mode
            if (this.visualizationMode === 'hexagon') {
                await this.updateVisualization();
            } else {
                this.layerManager.updateAllLayers(this.dataManager);
            }

        } catch (error) {
            console.error('Failed to refresh data:', error);
            alert('Failed to load GIS data');
        } finally {
            this.showLoading(false);
        }
    }

    toggleTracks() {
        if (!$('#showTracks').is(':checked')) {
            this.vesselManager.clearSelection();
        }
        this.layerManager.updateTrackLayer(
            $('#showTracks').is(':checked') ? this.vesselManager.getTracks() : []
        );
    }

    toggleAllTracks() {
        if ($('#showAllTracks').is(':checked')) {
            this.loadAllTracks();
        } else {
            this.dataManager.clearAllTracks();
            this.layerManager.updateAllTracksLayer([]);
        }
    }

    async loadAllTracks() {
        this.showLoading(true);
        try {
            const timeRange = $('#trackPeriod').val();
            await this.dataManager.loadAllTracks(timeRange);
            this.layerManager.updateAllTracksLayer(this.dataManager.getFilteredTracks());
        } catch (error) {
            console.error('Failed to load all tracks:', error);
        } finally {
            this.showLoading(false);
        }
    }

    toggleHeatmap() {
        if ($('#showHeatmap').is(':checked')) {
            alert('Density heatmap feature is coming soon!');
            $('#showHeatmap').prop('checked', false);
        }
    }

    // =====================================================
    // Visualization Mode Methods
    // =====================================================

    setVisualizationMode(mode) {
        this.visualizationMode = mode;

        if (mode === 'grid') {
            $('#gridLayerBtn').addClass('btn-primary active').removeClass('btn-outline-primary');
            $('#hexagonLayerBtn').addClass('btn-outline-primary').removeClass('btn-primary active');
            $('#gridLegend').show();
            $('#hexagonLegend').hide();
        } else {
            $('#hexagonLayerBtn').addClass('btn-primary active').removeClass('btn-outline-primary');
            $('#gridLayerBtn').addClass('btn-outline-primary').removeClass('btn-primary active');
            $('#gridLegend').hide();
            $('#hexagonLegend').show();
        }

        this.updateVisualization();
    }

    async updateVisualization() {
        if (this.visualizationMode === 'hexagon') {
            await this.loadVesselPositionsForHexagon();
            this.layerManager.updateHexagonLayer(this.vesselPositions, this.hexagonManager);
        } else {
            this.layerManager.removeHexagonLayer();
            this.layerManager.updateAllLayers(this.dataManager);
        }
    }

    async loadVesselPositionsForHexagon() {
        this.showLoading(true);
        try {
            const timeRange = $('#gisTimeRange').val();
            const positions = [];

            const haeguPromises = Object.entries(this.dataManager.haeguStats)
                .filter(([_, stats]) => stats.vessel_count > 0)
                .map(async ([haeguNo, _]) => {
                    try {
                        const data = await this.dataManager.loadVesselPositions('haegu', haeguNo, timeRange);
                        data.forEach(p => {
                            if (p.position && p.position.length >= 2) {
                                positions.push({
                                    position: p.position,
                                    count: 1,
                                    speed: p.speed || 0,
                                    vesselId: `${p.sig_src_cd}_${p.target_id}`,
                                    sig_src_cd: p.sig_src_cd,
                                    target_id: p.target_id
                                });
                            }
                        });
                    } catch (e) {
                        console.warn(`Failed to load positions for haegu ${haeguNo}:`, e);
                    }
                });

            await Promise.all(haeguPromises);

            this.vesselPositions = positions;
            this.hexagonManager.setPositions(positions);

            // Update legend stats
            $('#hexTotalVessels').text(positions.length);

            console.log(`Loaded ${positions.length} vessel positions for hexagon layer`);

        } catch (error) {
            console.error('Failed to load vessel positions:', error);
        } finally {
            this.showLoading(false);
        }
    }

    // =====================================================
    // Hexagon Click Handler
    // =====================================================

    handleHexagonClick(info) {
        if (!info.object) return;

        const points = info.object.points || [];
        const count = info.object.elevationValue || info.object.colorValue || points.length;

        console.log('Hexagon clicked:', { count, points: points.length });

        // Get vessels in this hexagon
        const vessels = this.hexagonManager.getVesselsInHexagon(info.object);

        if (vessels.length === 0) {
            alert('No vessel data available for this hexagon');
            return;
        }

        // Show vessel list
        this.showHexagonVesselList(vessels, info.coordinate);
    }

    showHexagonVesselList(vessels, coordinate) {
        const panel = $('#trackInfoPanel');
        const title = $('#trackPanelTitle');
        const content = $('#trackPanelContent');

        // Store for later use
        this.hexagonManager.setSelectedVessels(vessels);

        title.text(`Vessels in Hexagon (${vessels.length})`);

        let html = `
            <div class="mb-2">
                <strong>Location:</strong> ${coordinate[0].toFixed(4)}, ${coordinate[1].toFixed(4)}
            </div>
            <hr>
            <div class="mb-2">
                <button class="btn btn-sm btn-primary" onclick="GISApp.selectAllHexagonVessels()">
                    <i class="bi bi-check-all"></i> Select All
                </button>
                <button class="btn btn-sm btn-success ms-1" onclick="GISApp.showHexagonVesselTracks()">
                    <i class="bi bi-geo-alt"></i> Show Tracks
                </button>
            </div>
            <div style="max-height: 300px; overflow-y: auto;">
        `;

        vessels.forEach((v, idx) => {
            html += `
                <div class="vessel-item" data-vessel-id="${v.vesselId}" data-index="${idx}">
                    <input type="checkbox" class="vessel-checkbox hex-vessel-cb" data-index="${idx}">
                    <div class="vessel-info">
                        <strong>${v.vesselId}</strong><br>
                        <small>Speed: ${(v.speed || 0).toFixed(1)} kts</small>
                    </div>
                </div>
            `;
        });

        html += `
            </div>
            <hr>
            <button class="btn btn-sm btn-secondary w-100" onclick="$('#trackInfoPanel').hide()">
                <i class="bi bi-x"></i> Close
            </button>
        `;

        content.html(html);
        panel.show();

        // Bind checkbox events
        $('.hex-vessel-cb').on('change', function() {
            const idx = $(this).data('index');
            GISApp.hexagonManager.toggleVesselSelection(idx);
        });

        // Bind row click
        $('#trackPanelContent .vessel-item').on('click', function(e) {
            if (!$(e.target).is('.vessel-checkbox')) {
                const cb = $(this).find('.vessel-checkbox');
                cb.prop('checked', !cb.prop('checked')).trigger('change');
            }
        });
    }

    selectAllHexagonVessels() {
        this.hexagonManager.selectAllVessels();
        $('.hex-vessel-cb').prop('checked', true);
    }

    async showHexagonVesselTracks() {
        const selected = this.hexagonManager.getSelectedVesselIds();

        if (selected.length === 0) {
            alert('Please select at least one vessel');
            return;
        }

        this.showLoading(true);
        try {
            const timeRange = $('#gisTimeRange').val();
            const trackData = [];

            // Get unique haegu numbers from loaded data
            const haeguNumbers = Object.keys(this.dataManager.haeguStats)
                .filter(h => this.dataManager.haeguStats[h].vessel_count > 0);

            // Create a set of selected vessel IDs for quick lookup
            const selectedVesselIds = new Set(selected.map(v => v.vesselId));

            console.log('Selected vessels:', selectedVesselIds.size, Array.from(selectedVesselIds).slice(0, 3));

            // Load tracks from each haegu and filter by selected vessels
            for (const haeguNo of haeguNumbers) {
                try {
                    const tracks = await $.get(`/api/v1/tracks/haegu/${haeguNo}?minutes=${timeRange}`);

                    tracks.forEach(track => {
                        const vesselId = `${track.sig_src_cd}_${track.target_id}`;

                        if (selectedVesselIds.has(vesselId)) {
                            const path = Utils.parseLineStringM(track.track_geom);
                            if (path.length > 0) {
                                // Check if we already have this vessel's track
                                const existing = trackData.find(t => t.vessel_id === vesselId);
                                if (existing) {
                                    // Merge paths
                                    existing.path.push(...path);
                                    existing.distance += parseFloat(track.distance_nm) || 0;
                                } else {
                                    trackData.push({
                                        path: path,
                                        vessel_id: vesselId,
                                        distance: parseFloat(track.distance_nm) || 0,
                                        avg_speed: parseFloat(track.avg_speed) || 0,
                                        selected: true
                                    });
                                }
                            }
                        }
                    });
                } catch (e) {
                    console.warn(`Failed to load tracks from haegu ${haeguNo}:`, e);
                }
            }

            console.log('Found tracks for vessels:', trackData.length);

            if (trackData.length > 0) {
                $('#showTracks').prop('checked', true);
                this.layerManager.updateTrackLayer(trackData);

                const allPoints = trackData.flatMap(t => t.path);
                this.fitBounds(allPoints);

                $('#trackInfoPanel').hide();
            } else {
                alert('No tracks found for selected vessels in current time range');
            }
        } catch (error) {
            console.error('Failed to load vessel tracks:', error);
            alert('Failed to load vessel tracks');
        } finally {
            this.showLoading(false);
        }
    }

    // =====================================================
    // Area Details Methods
    // =====================================================

    showAreaDetails(type, properties) {
        const panel = $('#trackInfoPanel');
        const title = $('#trackPanelTitle');
        const content = $('#trackPanelContent');

        this.dataManager.setCurrentArea(type, properties.haegu_no || properties.area_id);

        const areaName = type === 'haegu' ?
            `Haegu ${properties.haegu_no}` :
            (properties.area_name || properties.area_id);

        title.text(areaName);
        content.html(this.generateAreaDetailsHTML(type, properties));
        panel.show();
    }

    generateAreaDetailsHTML(type, properties) {
        const id = type === 'haegu' ? properties.haegu_no : properties.area_id;
        return `
            <p><strong>Active Vessels:</strong> ${properties.vessel_count}</p>
            <p><strong>Total Distance:</strong> ${properties.total_distance.toFixed(2)} nm</p>
            <hr>
            <button class="btn btn-sm btn-primary" onclick="GISApp.showVesselList('${type}', '${id}')">
                <i class="bi bi-list"></i> Show Vessel List
            </button>
            <button class="btn btn-sm btn-success ms-2" onclick="GISApp.showVesselPositions('${type}', '${id}')">
                <i class="bi bi-geo-fill"></i> Show Positions
            </button>
            <br><br>
            <button class="btn btn-sm btn-warning w-100" onclick="GISApp.showAreaAllTracks('${type}', '${id}')">
                <i class="bi bi-map"></i> Show All Tracks in This Area
            </button>
            <br><br>
            <button class="btn btn-sm btn-secondary w-100" onclick="$('#trackInfoPanel').hide()">
                <i class="bi bi-x"></i> Close
            </button>
        `;
    }

    async showVesselList(type, id) {
        const timeRange = $('#gisTimeRange').val();
        $('#vesselListTitle').text(`Vessels in ${type === 'haegu' ? 'Haegu ' + id : 'Area'} (${timeRange} min)`);
        $('#vesselListSection').slideDown();

        this.showLoading(true);
        try {
            await this.vesselManager.loadVesselList(type, id, timeRange);
            this.vesselManager.sortAndRender();
        } catch (error) {
            console.error('Failed to load vessel list:', error);
            $('#vesselListContent').html('<div class="text-danger">Failed to load vessel list</div>');
        } finally {
            this.showLoading(false);
        }
    }

    async showVesselPositions(type, id) {
        this.showLoading(true);
        try {
            const timeRange = $('#gisTimeRange').val();
            const positions = await this.dataManager.loadVesselPositions(type, id, timeRange);
            this.layerManager.updatePositionLayer(positions);

            if (positions.length > 0) {
                this.fitBounds(positions.map(p => p.position));
            }
        } catch (error) {
            console.error('Failed to load vessel positions:', error);
        } finally {
            this.showLoading(false);
        }
    }

    async showAreaAllTracks(type, id) {
        this.showLoading(true);
        try {
            const period = $('#trackPeriod').val();
            const tracks = await this.dataManager.loadAreaTracks(type, id, period);

            $('#showTracks').prop('checked', true);
            this.layerManager.updateTrackLayer(tracks);

            if (tracks.length > 0) {
                const allPoints = tracks.flatMap(t => t.path);
                this.fitBounds(allPoints);
            }

            $('#trackPanelTitle').text(`All Tracks in ${type === 'haegu' ? 'Haegu ' + id : 'Area ' + id}`);
            $('#trackPanelContent').html(this.generateAreaTracksHTML(tracks.length, period));

        } catch (error) {
            console.error('Failed to load area tracks:', error);
        } finally {
            this.showLoading(false);
        }
    }

    generateAreaTracksHTML(trackCount, period) {
        return `
            <p><strong>Period:</strong> Last ${period} minutes</p>
            <p><strong>Total Vessels:</strong> ${trackCount}</p>
            <hr>
            <button class="btn btn-sm btn-primary" onclick="GISApp.backToAreaInfo()">
                <i class="bi bi-arrow-left"></i> Back to Area Info
            </button>
            <button class="btn btn-sm btn-secondary ms-2" onclick="GISApp.clearTracks()">
                <i class="bi bi-x-circle"></i> Clear Tracks
            </button>
        `;
    }

    async showSelectedTracks() {
        const selected = this.vesselManager.getSelectedVessels();
        if (selected.size === 0) {
            alert('Please select at least one vessel');
            return;
        }

        this.showLoading(true);
        try {
            const period = $('#trackPeriod').val();
            const tracks = await this.vesselManager.loadSelectedTracks(period);

            $('#showTracks').prop('checked', true);
            this.layerManager.updateTrackLayer(tracks);

            if (tracks.length > 0) {
                const allPoints = tracks.flatMap(t => t.path);
                this.fitBounds(allPoints);
            }

            $('#vesselListSection').slideUp();

        } catch (error) {
            console.error('Failed to load selected tracks:', error);
        } finally {
            this.showLoading(false);
        }
    }

    selectAllVessels() {
        this.vesselManager.selectAll();
    }

    deselectAllVessels() {
        this.vesselManager.deselectAll();
    }

    hideVesselList() {
        $('#vesselListSection').slideUp();
    }

    clearTracks() {
        this.vesselManager.clearSelection();
        this.dataManager.clearTracks();
        this.layerManager.updateTrackLayer([]);
    }

    backToAreaInfo() {
        const area = this.dataManager.getCurrentArea();
        if (area) {
            const stats = area.type === 'haegu' ?
                this.dataManager.haeguStats[area.id] :
                this.dataManager.areaStats[area.id];

            if (stats) {
                this.showAreaDetails(area.type, {
                    haegu_no: area.id,
                    area_id: area.id,
                    vessel_count: stats.vessel_count || 0,
                    total_distance: stats.total_distance || 0
                });
            }
        }
    }

    // =====================================================
    // Filter Methods
    // =====================================================

    applyFilters() {
        const filters = {
            minSpeed: parseFloat($('#minSpeedFilter').val()) || 0,
            maxSpeed: parseFloat($('#maxSpeedFilter').val()) || 50,
            minDist: parseFloat($('#minDistFilter').val()) || 0,
            maxDist: parseFloat($('#maxDistFilter').val()) || 200
        };

        this.dataManager.applyFilters(filters);
        this.vesselManager.applyFilters(filters);

        this.layerManager.updateTrackLayer(this.vesselManager.getTracks());
        this.layerManager.updateAllTracksLayer(this.dataManager.getFilteredTracks());
    }

    resetFilters() {
        $('#minSpeedFilter').val(0);
        $('#maxSpeedFilter').val(50);
        $('#minDistFilter').val(0);
        $('#maxDistFilter').val(200);

        this.dataManager.resetFilters();
        this.vesselManager.resetFilters();
        this.refreshData();
    }

    // =====================================================
    // Sequential Passage Methods
    // =====================================================

    toggleSequentialPanel() {
        $('#sequentialPanel').toggle();
    }

    addZone() {
        this.sequentialManager.addZone($('#zoneInput').val());
        $('#zoneInput').val('');
    }

    async searchSequentialPassage() {
        const mode = $('#passageMode').val();
        const type = $('#passageZoneType').val();
        const startTime = $('#passageStartTime').val();
        const endTime = $('#passageEndTime').val();
        const zones = this.sequentialManager.getZones();

        if (zones.length === 0) {
            alert('Please select at least one zone by right-clicking on the map');
            return;
        }

        if (mode === 'sequential' && zones.length !== 3) {
            alert('Sequential mode requires exactly 3 zones');
            return;
        }

        this.showLoading(true);
        try {
            const results = await this.sequentialManager.search(mode, type, startTime, endTime, zones);
            this.displaySequentialResults(results);
            this.sequentialManager.setResults(results);
        } catch (error) {
            console.error('Sequential passage search failed:', error);
            alert('Search failed. Please check your parameters.');
        } finally {
            this.showLoading(false);
        }
    }

    displaySequentialResults(results) {
        const container = $('#sequentialResults');

        if (!results || (results.passages?.length === 0 && results.vessels?.length === 0)) {
            container.html('<div class="text-muted">No vessels found</div>');
            return;
        }

        const vessels = results.passages || results.vessels || [];
        const totalCount = results.totalVessels || vessels.length;

        let html = `<h6>Found ${totalCount} vessels</h6>`;
        vessels.forEach(vessel => {
            const vesselId = vessel.sigSrcCd ?
                `${vessel.sigSrcCd}_${vessel.targetId}` :
                `${vessel.sig_src_cd}_${vessel.target_id}`;
            const shipName = vessel.vesselInfo?.shipName ||
                vessel.vesselInfo?.ship_name ||
                vessel.ship_name ||
                vesselId;

            html += `
                <div class="vessel-item" data-vessel-id="${vesselId}" style="cursor: pointer;">
                    <div class="vessel-info">
                        <strong>${vesselId}</strong><br>
                        <small>${shipName !== vesselId ? shipName : 'No name available'}</small>
                    </div>
                </div>
            `;
        });
        container.html(html);

        container.find('.vessel-item').on('click', function() {
            const vesselId = $(this).data('vessel-id');
            GISApp.selectSequentialVessel(vesselId);
        });
    }

    async selectSequentialVessel(vesselId) {
        const [sigSrcCd, ...targetIdParts] = vesselId.split('_');
        const targetId = targetIdParts.join('_');
        const startTime = $('#passageStartTime').val();
        const endTime = $('#passageEndTime').val();

        this.showLoading(true);
        try {
            const response = await $.ajax({
                url: '/api/v1/tracks/vessels',
                method: 'POST',
                contentType: 'application/json',
                data: JSON.stringify({
                    startTime: startTime + ':00',
                    endTime: endTime + ':00',
                    vessels: [{
                        sigSrcCd: sigSrcCd,
                        targetId: targetId
                    }]
                })
            });

            if (response && response.length > 0) {
                const vesselTrack = response[0];

                const trackData = [{
                    path: vesselTrack.geometry,
                    vessel_id: vesselTrack.vesselId,
                    distance: vesselTrack.totalDistance,
                    avg_speed: vesselTrack.avgSpeed,
                    max_speed: vesselTrack.maxSpeed,
                    selected: true
                }];

                $('#showTracks').prop('checked', true);
                this.layerManager.updateTrackLayer(trackData);

                if (vesselTrack.geometry.length > 0) {
                    this.fitBounds(vesselTrack.geometry);
                }

                $('#sequentialResults .vessel-item').removeClass('selected');
                $(`#sequentialResults .vessel-item[data-vessel-id="${vesselId}"]`).addClass('selected');
            } else {
                alert('No tracks found for this vessel in the specified time range');
            }
        } catch (error) {
            console.error('Failed to load vessel track:', error);
            alert('Failed to load vessel track. Please check the time range and try again.');
        } finally {
            this.showLoading(false);
        }
    }

    // =====================================================
    // Context Menu Methods
    // =====================================================

    showContextMenu(event, type, properties) {
        this.contextMenuTarget = { type, properties };

        const menu = $('#contextMenu');
        const addItem = $('#addToSequential');

        const currentZones = this.sequentialManager.getZones();
        const zoneId = type === 'haegu' ?
            properties.haegu_no.toString() :
            properties.area_id;

        if (currentZones.length >= 3) {
            addItem.addClass('disabled');
            addItem.html('<i class="bi bi-x-circle"></i> Max 3 zones');
        } else if (currentZones.includes(zoneId)) {
            addItem.addClass('disabled');
            addItem.html('<i class="bi bi-check-circle"></i> Already added');
        } else {
            addItem.removeClass('disabled');
            addItem.html('<i class="bi bi-plus-circle"></i> Add to Sequential');
        }

        menu.css({
            left: event.originalEvent.clientX + 'px',
            top: event.originalEvent.clientY + 'px',
            display: 'block'
        });
    }

    addToSequentialFromContext() {
        if (!this.contextMenuTarget) return;

        const { type, properties } = this.contextMenuTarget;
        const zoneId = type === 'haegu' ?
            properties.haegu_no.toString() :
            properties.area_id;

        this.sequentialManager.addZone(zoneId);

        if (!$('#sequentialPanel').is(':visible')) {
            $('#sequentialPanel').show();
        }

        $('#passageZoneType').val(type === 'haegu' ? 'GRID' : 'AREA');

        $('#contextMenu').hide();
    }

    viewAreaDetailsFromContext() {
        if (!this.contextMenuTarget) return;

        const { type, properties } = this.contextMenuTarget;
        this.showAreaDetails(type, properties);
        $('#contextMenu').hide();
    }

    // =====================================================
    // Utility Methods
    // =====================================================

    fitBounds(coordinates) {
        if (!coordinates || coordinates.length === 0) return;

        const bounds = new maplibregl.LngLatBounds();
        coordinates.forEach(coord => bounds.extend(coord));

        this.map.fitBounds(bounds, {
            padding: 50,
            duration: 1000
        });
    }

    getTooltip({object, layer}) {
        if (!object) return null;

        let html = null;

        if (layer.id === 'haegu-layer') {
            html = `<strong>Haegu ${object.properties.haegu_no}</strong><br>
                    Vessels: ${object.properties.vessel_count}<br>
                    Distance: ${object.properties.total_distance.toFixed(1)} nm`;
        } else if (layer.id === 'area-layer') {
            html = `<strong>${object.properties.area_name || object.properties.area_id}</strong><br>
                    Vessels: ${object.properties.vessel_count}<br>
                    Distance: ${object.properties.total_distance.toFixed(1)} nm`;
        } else if (layer.id === 'track-layer' || layer.id === 'all-tracks-layer') {
            html = `<strong>Vessel: ${object.vessel_id}</strong><br>
                    Avg Speed: ${object.avg_speed.toFixed(1)} kts<br>
                    Distance: ${object.distance.toFixed(1)} nm`;
        } else if (layer.id === 'hexagon-layer') {
            const count = object.elevationValue || object.colorValue || (object.points?.length || 0);
            html = `<strong>Vessel Density</strong><br>
                    Count: ${count} vessels<br>
                    <small><i class="bi bi-hand-index"></i> Click to see vessel list</small>`;
        }

        return html ? {
            html: html,
            style: {
                backgroundColor: 'rgba(255, 255, 255, 0.95)',
                color: '#000',
                fontSize: '12px',
                padding: '10px',
                borderRadius: '4px',
                boxShadow: '0 2px 4px rgba(0,0,0,0.3)'
            }
        } : null;
    }

    showLoading(show) {
        $('#loadingOverlay').css('display', show ? 'flex' : 'none');
    }
}

// =====================================================
// Hexagon Manager Class
// =====================================================
class HexagonManager {
    constructor() {
        this.positions = [];
        this.selectedVessels = [];
        this.vesselSelectionState = [];
        this.maxCount = 0;
    }

    setPositions(positions) {
        this.positions = positions;
    }

    getVesselsInHexagon(hexagonObject) {
        const points = hexagonObject.points || [];

        console.log('Points count:', points.length);

        const vessels = [];
        const seen = new Set(); // Deduplicate vessels

        for (const p of points) {
            let source = null;

            // Get source data from point
            if (p && p.source) {
                source = p.source;
            } else if (p && p.sig_src_cd) {
                source = p;
            }

            if (source && source.sig_src_cd && source.target_id) {
                const vesselId = source.vesselId || `${source.sig_src_cd}_${source.target_id}`;

                // Deduplicate by vesselId
                if (!seen.has(vesselId)) {
                    seen.add(vesselId);
                    vessels.push({
                        vesselId: vesselId,
                        sig_src_cd: source.sig_src_cd,
                        target_id: source.target_id,
                        speed: source.speed || 0,
                        position: source.position
                    });
                }
            }
        }

        console.log('Extracted unique vessels:', vessels.length);
        if (vessels.length > 0) {
            console.log('Sample vessel:', vessels[0]);
        }

        return vessels;
    }

    setSelectedVessels(vessels) {
        this.selectedVessels = vessels;
        this.vesselSelectionState = vessels.map(() => false);
    }

    toggleVesselSelection(index) {
        if (index >= 0 && index < this.vesselSelectionState.length) {
            this.vesselSelectionState[index] = !this.vesselSelectionState[index];
        }
    }

    selectAllVessels() {
        this.vesselSelectionState = this.vesselSelectionState.map(() => true);
    }

    getSelectedVesselIds() {
        return this.selectedVessels.filter((_, idx) => this.vesselSelectionState[idx]);
    }

    updateStats(maxCount) {
        this.maxCount = maxCount;
        $('#hexMaxCount').text(maxCount);

        // Update legend labels based on max count
        const step = Math.ceil(maxCount / 4);
        const labels = [0, step, step * 2, step * 3, maxCount + '+'];
        const labelElements = $('#hexagonLegendLabels span');
        labels.forEach((label, idx) => {
            if (labelElements[idx]) {
                $(labelElements[idx]).text(label);
            }
        });
    }
}

// =====================================================
// Data Manager Class
// =====================================================
class DataManager {
    constructor() {
        this.haegus = [];
        this.areas = [];
        this.haeguStats = {};
        this.areaStats = {};
        this.allTracks = [];
        this.filteredTracks = [];
        this.currentArea = null;
    }

    async loadHaeguData(timeRange) {
        const [boundaries, stats] = await Promise.all([
            $.get('/api/v1/haegu/boundaries'),
            $.get(`/api/v1/haegu/vessel-stats?minutes=${timeRange}`)
        ]);

        this.haegus = boundaries;
        this.haeguStats = stats;
        return { haegus: boundaries, stats };
    }

    async loadAreaData(timeRange) {
        const [boundaries, stats] = await Promise.all([
            $.get('/api/v1/areas/boundaries'),
            $.get(`/api/v1/areas/vessel-stats?minutes=${timeRange}`)
        ]);

        this.areas = boundaries;
        this.areaStats = stats;
        return { areas: boundaries, stats };
    }

    async loadAllTracks(timeRange) {
        this.allTracks = [];
        const layerType = $('#gisLayerType').val();

        const loadPromises = [];

        if (layerType === 'haegu' || layerType === 'both') {
            Object.entries(this.haeguStats).forEach(([haeguNo, stats]) => {
                if (stats.vessel_count > 0) {
                    loadPromises.push(
                        $.get(`/api/v1/tracks/haegu/${haeguNo}?minutes=${timeRange}`)
                            .then(tracks => this.processTracks(tracks, 'haegu', haeguNo))
                    );
                }
            });
        }

        if (layerType === 'area' || layerType === 'both') {
            Object.entries(this.areaStats).forEach(([areaId, stats]) => {
                if (stats.vessel_count > 0) {
                    loadPromises.push(
                        $.get(`/api/v1/tracks/area/${areaId}?minutes=${timeRange}`)
                            .then(tracks => this.processTracks(tracks, 'area', areaId))
                    );
                }
            });
        }

        await Promise.all(loadPromises);
        this.filteredTracks = [...this.allTracks];
        return this.filteredTracks;
    }

    async loadVesselPositions(type, id, timeRange) {
        const tracks = await $.get(`/api/v1/tracks/${type}/${id}?minutes=${timeRange}`);
        const latestPositions = {};

        tracks.forEach(track => {
            const vesselId = `${track.sig_src_cd}_${track.target_id}`;
            const path = Utils.parseLineStringM(track.track_geom);

            if (path.length > 0) {
                if (!latestPositions[vesselId] ||
                    new Date(track.time_bucket) > new Date(latestPositions[vesselId].time)) {
                    latestPositions[vesselId] = {
                        position: path[path.length - 1],
                        sig_src_cd: track.sig_src_cd,
                        target_id: track.target_id,
                        time: track.time_bucket,
                        speed: parseFloat(track.avg_speed) || 0
                    };
                }
            }
        });

        return Object.values(latestPositions);
    }

    async loadAreaTracks(type, id, period) {
        const tracks = await $.get(`/api/v1/tracks/${type}/${id}?minutes=${period}`);
        const vesselTracks = {};

        tracks.forEach(track => {
            const vesselId = `${track.sig_src_cd}_${track.target_id}`;
            if (!vesselTracks[vesselId]) {
                vesselTracks[vesselId] = {
                    vessel_id: vesselId,
                    tracks: [],
                    total_distance: 0,
                    avg_speeds: []
                };
            }
            vesselTracks[vesselId].tracks.push(track);
            vesselTracks[vesselId].total_distance += parseFloat(track.distance_nm) || 0;
            vesselTracks[vesselId].avg_speeds.push(parseFloat(track.avg_speed) || 0);
        });

        const processedTracks = [];
        Object.values(vesselTracks).forEach(vessel => {
            vessel.tracks.sort((a, b) => new Date(a.time_bucket) - new Date(b.time_bucket));

            const allPoints = [];
            vessel.tracks.forEach(track => {
                const points = Utils.parseLineStringM(track.track_geom);
                allPoints.push(...points);
            });

            if (allPoints.length > 0) {
                const avgSpeed = vessel.avg_speeds.reduce((a, b) => a + b, 0) / vessel.avg_speeds.length;
                processedTracks.push({
                    path: allPoints,
                    vessel_id: vessel.vessel_id,
                    distance: vessel.total_distance,
                    avg_speed: avgSpeed,
                    selected: false
                });
            }
        });

        return processedTracks;
    }

    processTracks(tracks, type, areaId) {
        tracks.forEach(track => {
            const path = Utils.parseLineStringM(track.track_geom);
            if (path.length > 0) {
                this.allTracks.push({
                    path: path,
                    vessel_id: `${track.sig_src_cd}_${track.target_id}`,
                    distance: parseFloat(track.distance_nm) || 0,
                    avg_speed: parseFloat(track.avg_speed) || 0,
                    time_bucket: track.time_bucket,
                    type: type,
                    area_id: areaId
                });
            }
        });
    }

    applyFilters(filters) {
        this.filteredTracks = this.allTracks.filter(track =>
            track.avg_speed >= filters.minSpeed &&
            track.avg_speed <= filters.maxSpeed &&
            track.distance >= filters.minDist &&
            track.distance <= filters.maxDist
        );
    }

    resetFilters() {
        this.filteredTracks = [...this.allTracks];
    }

    clearTracks() {
        this.allTracks = [];
        this.filteredTracks = [];
    }

    clearAllTracks() {
        this.allTracks = [];
        this.filteredTracks = [];
    }

    setCurrentArea(type, id) {
        this.currentArea = { type, id };
    }

    getCurrentArea() {
        return this.currentArea;
    }

    getFilteredTracks() {
        return this.filteredTracks;
    }
}

// =====================================================
// Vessel Manager Class
// =====================================================
class VesselManager {
    constructor() {
        this.vesselList = [];
        this.selectedVessels = new Set();
        this.tracks = [];
        this.currentArea = null;
    }

    async loadVesselList(type, id, timeRange) {
        this.currentArea = { type, id };

        const tracks = await $.get(`/api/v1/tracks/${type}/${id}?minutes=${timeRange}`);

        const vessels = tracks.map(t => ({
            id: `${t.sig_src_cd}_${t.target_id}`,
            sig_src_cd: t.sig_src_cd,
            target_id: t.target_id,
            distance: parseFloat(t.distance_nm) || 0,
            avg_speed: parseFloat(t.avg_speed) || 0,
            type: type,
            area_id: id,
            track_geom: t.track_geom,
            time_bucket: t.time_bucket
        }));

        const uniqueVessels = {};
        vessels.forEach(v => {
            if (!uniqueVessels[v.id] || uniqueVessels[v.id].distance < v.distance) {
                uniqueVessels[v.id] = v;
            }
        });

        this.vesselList = Object.values(uniqueVessels);
        return this.vesselList;
    }

    async loadSelectedTracks(period) {
        this.tracks = [];

        const trackPromises = [];

        for (const vessel of this.vesselList) {
            if (this.selectedVessels.has(vessel.id)) {
                trackPromises.push(
                    $.get(`/api/v1/tracks/${vessel.type}/${vessel.area_id}?minutes=${period}`)
                        .then(tracks => {
                            const vesselTracks = tracks.filter(t =>
                                `${t.sig_src_cd}_${t.target_id}` === vessel.id
                            );

                            const allPoints = [];
                            vesselTracks.forEach(track => {
                                const points = Utils.parseLineStringM(track.track_geom);
                                allPoints.push(...points);
                            });

                            if (allPoints.length > 0) {
                                this.tracks.push({
                                    path: allPoints,
                                    vessel_id: vessel.id,
                                    distance: vesselTracks.reduce((sum, t) => sum + (parseFloat(t.distance_nm) || 0), 0),
                                    avg_speed: vesselTracks.reduce((sum, t) => sum + (parseFloat(t.avg_speed) || 0), 0) / vesselTracks.length,
                                    selected: true
                                });
                            }
                        })
                );
            }
        }

        await Promise.all(trackPromises);
        return this.tracks;
    }

    sortAndRender() {
        const sortBy = $('#sortBy').val();
        const sortOrder = $('#sortOrder').val();

        this.vesselList.sort((a, b) => {
            let compareValue = 0;

            switch (sortBy) {
                case 'id':
                    compareValue = a.id.localeCompare(b.id);
                    break;
                case 'speed':
                    compareValue = a.avg_speed - b.avg_speed;
                    break;
                case 'distance':
                    compareValue = a.distance - b.distance;
                    break;
            }

            return sortOrder === 'asc' ? compareValue : -compareValue;
        });

        this.render();
    }

    render() {
        const content = $('#vesselListContent');

        if (this.vesselList.length === 0) {
            content.html('<div class="text-muted">No vessels found in this area</div>');
            return;
        }

        let html = `<div class="mb-2">Found ${this.vesselList.length} vessels</div>`;

        this.vesselList.forEach(v => {
            const isSelected = this.selectedVessels.has(v.id);
            html += `
                <div class="vessel-item ${isSelected ? 'selected' : ''}" data-vessel-id="${v.id}">
                    <input type="checkbox" class="vessel-checkbox"
                           data-vessel-id="${v.id}"
                           ${isSelected ? 'checked' : ''}>
                    <div class="vessel-info">
                        <strong>${v.id}</strong><br>
                        <small>
                            Distance: ${v.distance.toFixed(2)} nm |
                            Avg Speed: ${v.avg_speed.toFixed(1)} kts
                        </small>
                    </div>
                </div>
            `;
        });

        content.html(html);

        $('.vessel-checkbox').off('change').on('change', function (e) {
            e.stopPropagation();
            const vesselId = $(this).data('vessel-id');
            GISApp.vesselManager.toggleSelection(vesselId);
        });

        $('.vessel-item').off('click').on('click', function (e) {
            if (!$(e.target).is('.vessel-checkbox')) {
                const checkbox = $(this).find('.vessel-checkbox');
                checkbox.prop('checked', !checkbox.prop('checked'));
                const vesselId = $(this).data('vessel-id');
                GISApp.vesselManager.toggleSelection(vesselId);
            }
        });

        this.updateSelectedCount();
    }

    toggleSelection(vesselId) {
        if (this.selectedVessels.has(vesselId)) {
            this.selectedVessels.delete(vesselId);
        } else {
            this.selectedVessels.add(vesselId);
        }

        const vesselItem = $(`.vessel-item[data-vessel-id="${vesselId}"]`);
        const checkbox = vesselItem.find('.vessel-checkbox');

        if (this.selectedVessels.has(vesselId)) {
            vesselItem.addClass('selected');
            checkbox.prop('checked', true);
        } else {
            vesselItem.removeClass('selected');
            checkbox.prop('checked', false);
        }

        this.updateSelectedCount();
    }

    selectAll() {
        this.vesselList.forEach(v => this.selectedVessels.add(v.id));
        this.render();
    }

    deselectAll() {
        this.selectedVessels.clear();
        this.render();
    }

    clearSelection() {
        this.selectedVessels.clear();
        this.tracks = [];
        this.updateSelectedCount();
    }

    applyFilters(filters) {
        const originalList = [...this.vesselList];
        this.vesselList = originalList.filter(v =>
            v.avg_speed >= filters.minSpeed &&
            v.avg_speed <= filters.maxSpeed &&
            v.distance >= filters.minDist &&
            v.distance <= filters.maxDist
        );
        this.render();
    }

    resetFilters() {
        if (this.currentArea) {
            this.loadVesselList(
                this.currentArea.type,
                this.currentArea.id,
                $('#gisTimeRange').val()
            ).then(() => this.sortAndRender());
        }
    }

    updateSelectedCount() {
        const count = this.selectedVessels.size;
        const countElement = $('#selectedCount');

        if (count > 0) {
            countElement.text(count).show();
        } else {
            countElement.hide();
        }
    }

    getSelectedVessels() {
        return this.selectedVessels;
    }

    getTracks() {
        return this.tracks;
    }
}

// =====================================================
// Layer Manager Class
// =====================================================
class LayerManager {
    constructor(deckOverlay) {
        this.deckOverlay = deckOverlay;
        this.layers = new Map();
        this.hexagonManager = null;
    }

    updateAllLayers(dataManager) {
        const layers = [];
        const layerType = $('#gisLayerType').val();

        if ((layerType === 'haegu' || layerType === 'both') && dataManager.haegus.length > 0) {
            layers.push(this.createHaeguLayer(dataManager.haegus, dataManager.haeguStats));
        }

        if ((layerType === 'area' || layerType === 'both') && dataManager.areas.length > 0) {
            layers.push(this.createAreaLayer(dataManager.areas, dataManager.areaStats));
        }

        if (this.layers.has('track-layer')) {
            layers.push(this.layers.get('track-layer'));
        }
        if (this.layers.has('all-tracks-layer')) {
            layers.push(this.layers.get('all-tracks-layer'));
        }
        if (this.layers.has('position-layer')) {
            layers.push(this.layers.get('position-layer'));
        }

        this.deckOverlay.setProps({ layers });
    }

    createHaeguLayer(haegus, stats) {
        const layer = new deck.GeoJsonLayer({
            id: 'haegu-layer',
            data: {
                type: 'FeatureCollection',
                features: haegus.map(haegu => ({
                    type: 'Feature',
                    properties: {
                        haegu_no: haegu.haegu_no,
                        vessel_count: stats?.[haegu.haegu_no]?.vessel_count || 0,
                        total_distance: stats?.[haegu.haegu_no]?.total_distance || 0
                    },
                    geometry: JSON.parse(haegu.geom_json)
                }))
            },
            filled: true,
            stroked: true,
            getFillColor: d => Utils.getVesselCountColor(d.properties.vessel_count),
            getLineColor: [0, 100, 200, 255],
            getLineWidth: 2,
            lineWidthMinPixels: 1,
            pickable: true,
            autoHighlight: true,
            highlightColor: [255, 255, 0, 100],
            onClick: (info) => {
                if (info.object) {
                    GISApp.showAreaDetails('haegu', info.object.properties);
                }
                return true;
            }
        });

        this.layers.set('haegu-layer', layer);
        return layer;
    }

    createAreaLayer(areas, stats) {
        const layer = new deck.GeoJsonLayer({
            id: 'area-layer',
            data: {
                type: 'FeatureCollection',
                features: areas.map(area => ({
                    type: 'Feature',
                    properties: {
                        area_id: area.area_id,
                        area_name: area.area_name,
                        vessel_count: stats?.[area.area_id]?.vessel_count || 0,
                        total_distance: stats?.[area.area_id]?.total_distance || 0
                    },
                    geometry: JSON.parse(area.geom_json)
                }))
            },
            filled: true,
            stroked: true,
            getFillColor: d => Utils.getVesselCountColor(d.properties.vessel_count),
            getLineColor: [200, 100, 0, 255],
            getLineWidth: 3,
            lineWidthMinPixels: 2,
            pickable: true,
            autoHighlight: true,
            highlightColor: [255, 255, 0, 100],
            onClick: (info) => {
                if (info.object) {
                    GISApp.showAreaDetails('area', info.object.properties);
                }
                return true;
            }
        });

        this.layers.set('area-layer', layer);
        return layer;
    }

    updateTrackLayer(tracks) {
        if (!tracks || tracks.length === 0) {
            this.layers.delete('track-layer');
        } else {
            const layer = new deck.PathLayer({
                id: 'track-layer',
                data: tracks,
                getPath: d => d.path,
                getColor: d => d.selected ? [0, 128, 255, 255] : [0, 255, 0, 255],
                getWidth: d => d.selected ? 4 : 3,
                pickable: true,
                widthMinPixels: 2,
                widthMaxPixels: 10,
                capRounded: true,
                jointRounded: true,
                billboard: false
            });

            this.layers.set('track-layer', layer);
        }

        this.updateDeckLayers();
    }

    updateAllTracksLayer(tracks) {
        if (!tracks || tracks.length === 0) {
            this.layers.delete('all-tracks-layer');
        } else {
            const layer = new deck.PathLayer({
                id: 'all-tracks-layer',
                data: tracks,
                getPath: d => d.path,
                getColor: d => {
                    if (d.avg_speed > 20) return [255, 0, 0, 200];
                    if (d.avg_speed > 10) return [255, 165, 0, 200];
                    return [0, 128, 255, 200];
                },
                getWidth: 2,
                pickable: true,
                widthMinPixels: 1,
                widthMaxPixels: 5,
                capRounded: true,
                jointRounded: true,
                billboard: false
            });

            this.layers.set('all-tracks-layer', layer);
        }

        this.updateDeckLayers();
    }

    updatePositionLayer(positions) {
        if (!positions || positions.length === 0) {
            this.layers.delete('position-layer');
        } else {
            const layer = new deck.ScatterplotLayer({
                id: 'position-layer',
                data: positions,
                getPosition: d => d.position,
                getRadius: 4,
                radiusMinPixels: 3,
                radiusMaxPixels: 8,
                getFillColor: [255, 0, 0, 255],
                getLineColor: [255, 255, 255, 255],
                lineWidthMinPixels: 1,
                pickable: true
            });

            this.layers.set('position-layer', layer);
        }

        this.updateDeckLayers();
    }

    updateDeckLayers() {
        this.deckOverlay.setProps({ layers: Array.from(this.layers.values()) });
    }

    /**
     * Create and update Hexagon Layer for vessel density visualization
     */
    updateHexagonLayer(positions, hexagonManager) {
        this.hexagonManager = hexagonManager;

        this.layers.delete('haegu-layer');
        this.layers.delete('area-layer');

        if (!positions || positions.length === 0) {
            console.warn('No positions for hexagon layer');
            this.layers.delete('hexagon-layer');
            this.updateDeckLayers();
            return;
        }

        const COLOR_RANGE = [
            [1, 152, 189],
            [73, 227, 206],
            [216, 254, 181],
            [254, 237, 177],
            [254, 173, 84],
            [209, 55, 78]
        ];

        const hexagonLayer = new deck.HexagonLayer({
            id: 'hexagon-layer',
            data: positions,
            getPosition: d => d.position,

            radius: 5000,
            coverage: 0.9,

            extruded: true,
            elevationScale: 100,
            elevationRange: [0, 3000],

            colorRange: COLOR_RANGE,
            colorAggregation: 'SUM',

            // Use CPU aggregation to preserve original data in points
            gpuAggregation: false,

            pickable: true,
            autoHighlight: true,

            material: {
                ambient: 0.64,
                diffuse: 0.6,
                shininess: 32,
                specularColor: [51, 51, 51]
            },

            transitions: {
                elevationScale: 500
            },

            // Click handler for hexagon
            onClick: (info) => {
                if (info.object) {
                    GISApp.handleHexagonClick(info);
                }
                return true;
            },

            // Update stats when data changes
            onSetColorDomain: (domain) => {
                if (domain && domain.length > 1) {
                    hexagonManager.updateStats(domain[1]);
                }
            }
        });

        this.layers.set('hexagon-layer', hexagonLayer);
        this.updateDeckLayers();

        console.log(`Hexagon layer created with ${positions.length} points`);
    }

    removeHexagonLayer() {
        this.layers.delete('hexagon-layer');
    }
}

// =====================================================
// Sequential Passage Manager Class
// =====================================================
class SequentialPassageManager {
    constructor() {
        this.zones = [];
        this.maxZones = 3;
        this.results = null;
    }

    addZone(zoneId) {
        if (!zoneId) return false;

        if (this.zones.length >= this.maxZones) {
            alert(`Maximum ${this.maxZones} zones allowed`);
            return false;
        }

        if (this.zones.includes(zoneId)) {
            alert('Zone already added');
            return false;
        }

        this.zones.push(zoneId);
        this.renderZones();
        console.log('Added zone:', zoneId, 'Total zones:', this.zones);
        return true;
    }

    removeZone(index) {
        this.zones.splice(index, 1);
        this.renderZones();
    }

    renderZones() {
        const container = $('#selectedZones');

        if (this.zones.length === 0) {
            container.html('<small class="text-muted">No zones selected</small>');
            return;
        }

        let html = '';
        this.zones.forEach((zone, index) => {
            html += `
                <span class="zone-tag">
                    ${zone}
                    <span class="remove-zone" onclick="GISApp.sequentialManager.removeZone(${index})">
                        <i class="bi bi-x"></i>
                    </span>
                </span>
            `;
        });

        container.html(html);
    }

    async search(mode, type, startTime, endTime, zones) {
        const endpoint = mode === 'sequential' ?
            '/api/v1/passages/sequential' :
            '/api/v1/passages/all-zones';

        const formattedStartTime = startTime.includes('T') ?
            startTime + ':00' : startTime;
        const formattedEndTime = endTime.includes('T') ?
            endTime + ':00' : endTime;

        const response = await $.ajax({
            url: endpoint,
            method: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({
                type: type,
                zoneIds: zones,
                startTime: formattedStartTime,
                endTime: formattedEndTime
            })
        });

        return response;
    }

    getZones() {
        return this.zones;
    }

    clearZones() {
        this.zones = [];
        this.renderZones();
    }

    setResults(results) {
        this.results = results;
    }

    getResults() {
        return this.results;
    }
}

// =====================================================
// Utility Functions
// =====================================================
class Utils {
    static parseLineStringM(wkt) {
        if (!wkt) return [];

        const matches = wkt.match(/LINESTRING M\s*\((.*)\)/);
        if (!matches) return [];

        try {
            const coords = matches[1].split(',').map(coord => {
                const parts = coord.trim().split(/\s+/);
                const lon = parseFloat(parts[0]);
                const lat = parseFloat(parts[1]);

                if (isNaN(lon) || isNaN(lat)) return null;

                return [lon, lat];
            }).filter(coord => coord !== null);

            return coords;
        } catch (error) {
            console.error('Error parsing LineStringM:', error);
            return [];
        }
    }

    static getVesselCountColor(count) {
        if (count >= 200) return [255, 69, 0, 150];
        if (count >= 100) return [255, 165, 0, 150];
        if (count >= 50) return [255, 215, 0, 150];
        if (count >= 10) return [144, 238, 144, 150];
        if (count > 0) return [224, 224, 224, 150];
        return [224, 224, 224, 50];
    }
}

// =====================================================
// Initialize Application
// =====================================================
let GISApp;
$(document).ready(function () {
    GISApp = new GISMonitoringApp();
});

