<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Offline Map Tile Downloader</title>
    <link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
    <link rel="stylesheet" href="/static/leaflet.css" />
    <link rel="stylesheet" href="/static/leaflet.draw.css" />
    <script src="/static/leaflet.js"></script>
    <script src="/static/leaflet.draw.js"></script>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
        }
        #map {
            height: 100vh;
            width: 100%;
        }
        .form-container {
            position: absolute;
            top: 8px;
            right: 10px;
            z-index: 1000;
            background: rgba(234, 233, 233, 0.822);
            padding: 10px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0,0,0,0.5);
        }
        #progress {
            position: absolute;
            top: 250px;
            right: 11px;
            z-index: 1000;
            background: rgba(241, 242, 243, 0.736);
            padding: 10px;
            border-radius: 5px;
            box-shadow: 2px 4px 8px rgba(0,0.2,0,0.5);
        }
    </style>
</head>
<body>
    <div style="position: relative;">
        <div id="map"></div>
        <div class="form-container">
            <div style="margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #ccc;">
                <label for="coord_search">Go to Coordinates:</label><br>
                <input type="text" id="coord_search" placeholder="lat, lng (e.g. 53.55, 10)" style="width: 200px;">
                <button type="button" id="goToBtn">Go</button>
            </div>
            <form id="downloadForm">
                <label for="map_style">Map Style:</label>
                <select id="map_style" name="map_style"></select><br>
                <label for="min_zoom">Min. Zoom:</label>
                <input type="number" id="min_zoom" name="min_zoom" min="0" max="19" value="8"><br>
                <label for="max_zoom">Max. Zoom:</label>
                <input type="number" id="max_zoom" name="max_zoom" min="0" max="19" value="12"><br>
                <input type="checkbox" id="view_cached_tiles">
                <label for="view_cached_tiles">Show offline map coverage</label><br>
                <input type="checkbox" id="use_cache" name="use_cache">
                <label for="use_cache">Enable offline mode</label><br>
                <input type="checkbox" id="convert_to_8bit" checked>
                <label for="convert_to_8bit">Convert to 8-bit</label><br>
                <button type="button" id="downloadBtn">💾 Download Tiles</button>
                <button type="button" id="downloadWorldBtn">🗺️ Download World Basemap</button>
                <button type="button" id="cancelBtn" disabled>❌ Cancel Download</button>
            </form>
        </div>
        <div id="progress">Ready</div>
    </div>

    <script>
        const socket = new WebSocket(`ws://${window.location.host}/ws`);

        socket.onopen = () => {
            console.log("WebSocket connection established");
        };

        socket.onclose = () => {
            console.log("WebSocket connection closed");
        };

        socket.onerror = (error) => {
            console.error("WebSocket error:", error);
        };

        var map = L.map('map').setView([53.55, 10], 13);
        var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
            maxZoom: 19
        }).addTo(map);

        // Coordinate search functionality
        document.getElementById('goToBtn').addEventListener('click', function() {
            var input = document.getElementById('coord_search').value.trim();
            var parts = input.split(',');
            if (parts.length === 2) {
                var lat = parseFloat(parts[0].trim());
                var lng = parseFloat(parts[1].trim());
                if (!isNaN(lat) && !isNaN(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
                    map.setView([lat, lng], 13);
                } else {
                    alert('Invalid coordinates. Latitude must be -90 to 90, longitude must be -180 to 180.');
                }
            } else {
                alert('Please enter coordinates in format: lat, lng');
            }
        });

        document.getElementById('coord_search').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                e.preventDefault();
                document.getElementById('goToBtn').click();
            }
        });

        var drawnItems = new L.FeatureGroup();
        map.addLayer(drawnItems);
        var drawControl = new L.Control.Draw({
            draw: { polygon: true, marker: false, circle: false, circlemarker: false, polyline: false, rectangle: true },
            edit: { featureGroup: drawnItems }
        });
        map.addControl(drawControl);

        map.on('draw:created', function(e) {
            drawnItems.addLayer(e.layer);
            document.getElementById('downloadBtn').disabled = drawnItems.getLayers().length === 0;
        });

        map.on('draw:deleted', function() {
            document.getElementById('downloadBtn').disabled = drawnItems.getLayers().length === 0;
        });

        var missingTilesLayer = L.layerGroup().addTo(map);
        var cachedTilesLayer = L.layerGroup().addTo(map);
        var downloadProgressLayer = L.layerGroup().addTo(map);

        function onTileError(e) {
            var coords = e.coords;
            var z = coords.z;
            var x = coords.x;
            var y = coords.y;
            var topLeft = map.unproject([x * 256, y * 256], z);
            var bottomRight = map.unproject([(x + 1) * 256, (y + 1) * 256], z);
            var bounds = L.latLngBounds(topLeft, bottomRight);
            L.rectangle(bounds, { color: "red", weight: 1, fill: false }).addTo(missingTilesLayer);
        }

        function sanitizeStyleName(name) {
            name = name.replace(/\s+/g, '-');
            name = name.replace(/[^a-zA-Z0-9-_]/g, '');
            return name;
        }

        function updateTileLayer() {
            var mapStyleSelect = document.getElementById('map_style');
            var mapStyleUrl = mapStyleSelect.value;
            var styleName = sanitizeStyleName(mapStyleSelect.options[mapStyleSelect.selectedIndex].text);
            var useCache = document.getElementById('use_cache').checked;
            var tileUrl = useCache ? `/tiles/${styleName}/{z}/{x}/{y}.png` : mapStyleUrl;
            tileLayer.setUrl(tileUrl);
            tileLayer.off('loading');
            tileLayer.off('tileerror', onTileError);
            missingTilesLayer.clearLayers();
            if (useCache) {
                tileLayer.on('loading', function() {
                    missingTilesLayer.clearLayers();
                });
                tileLayer.on('tileerror', onTileError);
            }
        }

        fetch('/get_map_sources')
            .then(response => response.json())
            .then(data => {
                var select = document.getElementById('map_style');
                for (var name in data) {
                    var option = document.createElement('option');
                    option.value = data[name];
                    option.text = name;
                    select.appendChild(option);
                }
                updateTileLayer();
            });

        document.getElementById('map_style').addEventListener('change', function() {
            updateTileLayer();
            if (document.getElementById('view_cached_tiles').checked) {
                showCachedTiles();
            }
        });
        document.getElementById('use_cache').addEventListener('change', updateTileLayer);

        const minZoomInput = document.getElementById('min_zoom');
        const maxZoomInput = document.getElementById('max_zoom');

        minZoomInput.addEventListener('change', function() {
            if (parseInt(this.value) > parseInt(maxZoomInput.value)) {
                maxZoomInput.value = this.value;
            }
        });

        maxZoomInput.addEventListener('change', function() {
            if (parseInt(this.value) < parseInt(minZoomInput.value)) {
                minZoomInput.value = this.value;
            }
        });

        document.getElementById('downloadBtn').addEventListener('click', function() {
            var polygons = [];
            drawnItems.eachLayer(function(layer) {
                if (layer instanceof L.Polygon || layer instanceof L.Rectangle) {
                    var latlngs = layer.getLatLngs()[0];
                    polygons.push(latlngs.map(function(latlng) { return {lat: latlng.lat, lng: latlng.lng}; }));
                }
            });
            if (polygons.length === 0) {
                alert('Please draw at least one shape.');
                return;
            }
            var data = {
                type: 'start_download',
                data: {
                    polygons: polygons,
                    min_zoom: parseInt(document.getElementById('min_zoom').value),
                    max_zoom: parseInt(document.getElementById('max_zoom').value),
                    map_style: document.getElementById('map_style').value,
                    convert_to_8bit: document.getElementById('convert_to_8bit').checked
                }
            };
            console.log('Sending download request with data:', JSON.stringify(data, null, 2));
            socket.send(JSON.stringify(data));
        });

        document.getElementById('downloadWorldBtn').addEventListener('click', function() {
            var data = {
                type: 'start_world_download',
                data: {
                    map_style: document.getElementById('map_style').value,
                    convert_to_8bit: document.getElementById('convert_to_8bit').checked
                }
            };
            socket.send(JSON.stringify(data));
        });

        document.getElementById('cancelBtn').addEventListener('click', function() {
            socket.send(JSON.stringify({type: 'cancel_download'}));
        });

        document.getElementById('view_cached_tiles').addEventListener('change', function() {
            if (this.checked) {
                showCachedTiles();
            } else {
                cachedTilesLayer.clearLayers();
            }
        });

        function showCachedTiles() {
            cachedTilesLayer.clearLayers();
            var mapStyleSelect = document.getElementById('map_style');
            var styleName = sanitizeStyleName(mapStyleSelect.options[mapStyleSelect.selectedIndex].text);
            fetch(`/get_cached_tiles/${styleName}`)
                .then(response => response.json())
                .then(data => {
                    if (!data) return;
                    data.forEach(function(tile) {
                        var z = tile[0], x = tile[1], y = tile[2];
                        var topLeft = map.unproject([x * 256, y * 256], z);
                        var bottomRight = map.unproject([(x + 1) * 256, (y + 1) * 256], z);
                        var bounds = L.latLngBounds(topLeft, bottomRight);
                        L.rectangle(bounds, { color: "#0000ff", weight: 1, fill: false }).addTo(cachedTilesLayer);
                    });
                });
        }

        var totalTiles = 0;
        var downloadedTiles = 0;
        var skippedTiles = 0;
        var failedTiles = 0;

        socket.onmessage = (event) => {
            const message = JSON.parse(event.data);
            const data = message.data;

            switch (message.type) {
                case 'download_started':
                    totalTiles = data.total_tiles;
                    downloadedTiles = 0;
                    skippedTiles = 0;
                    failedTiles = 0;
                    downloadProgressLayer.clearLayers();
                    document.getElementById('downloadBtn').disabled = true;
                    document.getElementById('downloadWorldBtn').disabled = true;
                    document.getElementById('cancelBtn').disabled = false;
                    updateProgress();
                    break;
                case 'tile_downloaded':
                    downloadedTiles++;
                    updateProgress();
                    var bounds = [[data.south, data.west], [data.north, data.east]];
                    L.rectangle(bounds, { color: "#ff7800", weight: 1, fill: false }).addTo(downloadProgressLayer);
                    break;
                case 'tile_skipped':
                    skippedTiles++;
                    updateProgress();
                    var bounds = [[data.south, data.west], [data.north, data.east]];
                    L.rectangle(bounds, { color: "#00ff00", weight: 1, fill: false }).addTo(downloadProgressLayer);
                    break;
                case 'tile_failed':
                    failedTiles++;
                    updateProgress();
                    break;
                case 'download_complete':
                    document.getElementById('downloadBtn').disabled = false;
                    document.getElementById('downloadWorldBtn').disabled = false;
                    document.getElementById('cancelBtn').disabled = true;
                    downloadProgressLayer.clearLayers();
                    var summary = `✅ Download complete!<br>` +
                                  `Downloaded: ${downloadedTiles}<br>` +
                                  `Skipped: ${skippedTiles}<br>` +
                                  `Failed: ${failedTiles}<br>` +
                                  `Total queued: ${totalTiles}`;
                    document.getElementById('progress').innerHTML = summary;
                    break;
                case 'download_cancelled':
                    document.getElementById('downloadBtn').disabled = false;
                    document.getElementById('downloadWorldBtn').disabled = false;
                    document.getElementById('cancelBtn').disabled = true;
                    downloadProgressLayer.clearLayers();
                    document.getElementById('progress').innerHTML = 'Ready';
                    alert('Download cancelled');
                    break;
                case 'error':
                    document.getElementById('downloadBtn').disabled = false;
                    document.getElementById('downloadWorldBtn').disabled = false;
                    document.getElementById('cancelBtn').disabled = true;
                    document.getElementById('progress').innerHTML = 'Ready';
                    alert(data.message);
                    break;
            }
        };

        function updateProgress() {
            if (totalTiles === 0) {
                document.getElementById('progress').innerHTML = 'Starting...';
                return;
            }
            var progress = ((downloadedTiles + skippedTiles + failedTiles) / totalTiles * 100).toFixed(2);
            var progressText = `⏳ Downloading: ${progress}%<br>` +
                               `Downloaded: ${downloadedTiles}<br>` +
                               `Skipped: ${skippedTiles}<br>` +
                               `Failed: ${failedTiles}<br>` +
                               `Total queued: ${totalTiles}`;
            document.getElementById('progress').innerHTML = progressText;
        }
    </script>
</body>
</html>
