"""
Script pour générer une page HTML interactive avec les données des villages corses embarquées.
Usage: python generate_interactive_map.py villages_corse.csv
"""

import csv
import json
import sys

def parse_coordinates(point_geo_str):
    """Parse la colonne Point_Geo"""
    try:
        parts = point_geo_str.split(',')
        lat = float(parts[0].strip())
        lon = float(parts[1].strip())
        return lat, lon
    except:
        return None, None

def load_villages_from_csv(csv_file):
    """Charge les villages depuis le CSV"""
    villages = []
    
    with open(csv_file, 'r', encoding='utf-8') as f:
        reader = csv.reader(f, delimiter=';')
        next(reader)  # Skip header
        
        for row in reader:
            if len(row) >= 18:
                lat, lon = parse_coordinates(row[17])
                if lat and lon:
                    villages.append({
                        'name': row[0],
                        'nameCorse': row[1],
                        'lat': lat,
                        'lon': lon,
                        'dept': row[9],
                        'altitude': float(row[15]) if row[15] else 0
                    })
    
    return villages

def generate_html(villages, output_file='knn_interactive_full.html'):
    """Génère le fichier HTML avec les données embarquées"""
    
    villages_json = json.dumps(villages, ensure_ascii=False)
    
    html_content = f'''<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Classification k-NN Interactive - Corse</title>
    
    <!-- Leaflet CSS -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    
    <style>
        * {{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }}
        
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }}
        
        .container {{
            max-width: 1400px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 10px 40px rgba(0,0,0,0.3);
        }}
        
        .header {{
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }}
        
        .header h1 {{
            font-size: 2.5em;
            margin-bottom: 10px;
        }}
        
        .header p {{
            font-size: 1.2em;
            opacity: 0.9;
        }}
        
        .main-content {{
            display: grid;
            grid-template-columns: 350px 1fr;
            gap: 0;
        }}
        
        .sidebar {{
            background: #f5f5f5;
            padding: 30px;
            border-right: 2px solid #ddd;
            max-height: 900px;
            overflow-y: auto;
        }}
        
        .controls {{
            background: white;
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        
        .controls h3 {{
            margin-bottom: 15px;
            color: #333;
            font-size: 1.2em;
        }}
        
        .control-group {{
            margin-bottom: 20px;
        }}
        
        .control-group label {{
            display: block;
            font-weight: bold;
            color: #555;
            margin-bottom: 8px;
        }}
        
        .slider-container {{
            display: flex;
            align-items: center;
            gap: 10px;
        }}
        
        input[type="range"] {{
            flex: 1;
            height: 8px;
            border-radius: 5px;
            background: #ddd;
            outline: none;
        }}
        
        input[type="range"]::-webkit-slider-thumb {{
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #667eea;
            cursor: pointer;
        }}
        
        input[type="range"]::-moz-range-thumb {{
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #667eea;
            cursor: pointer;
            border: none;
        }}
        
        .k-value {{
            background: #667eea;
            color: white;
            padding: 5px 15px;
            border-radius: 20px;
            font-weight: bold;
            min-width: 40px;
            text-align: center;
        }}
        
        .result-box {{
            background: white;
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        
        .result-box h3 {{
            margin-bottom: 15px;
            color: #333;
        }}
        
        .prediction {{
            font-size: 1.3em;
            font-weight: bold;
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            margin-bottom: 15px;
        }}
        
        .prediction.corse-sud {{
            background: #ffebee;
            color: #c62828;
        }}
        
        .prediction.haute-corse {{
            background: #e3f2fd;
            color: #1565c0;
        }}
        
        .prediction.no-result {{
            background: #f5f5f5;
            color: #666;
        }}
        
        .coords {{
            font-size: 0.9em;
            color: #666;
            text-align: center;
            margin-bottom: 10px;
        }}
        
        .votes {{
            display: flex;
            justify-content: space-around;
            margin-bottom: 15px;
        }}
        
        .vote-item {{
            text-align: center;
        }}
        
        .vote-count {{
            font-size: 2em;
            font-weight: bold;
        }}
        
        .vote-count.red {{
            color: #c62828;
        }}
        
        .vote-count.blue {{
            color: #1565c0;
        }}
        
        .neighbors-list {{
            max-height: 300px;
            overflow-y: auto;
            background: #fafafa;
            padding: 10px;
            border-radius: 5px;
        }}
        
        .neighbor-item {{
            padding: 10px;
            margin-bottom: 8px;
            background: white;
            border-radius: 5px;
            border-left: 4px solid #ddd;
        }}
        
        .neighbor-item.dept-2a {{
            border-left-color: #c62828;
        }}
        
        .neighbor-item.dept-2b {{
            border-left-color: #1565c0;
        }}
        
        .neighbor-name {{
            font-weight: bold;
            margin-bottom: 3px;
        }}
        
        .neighbor-corse {{
            font-style: italic;
            color: #666;
            font-size: 0.9em;
        }}
        
        .neighbor-distance {{
            font-size: 0.9em;
            color: #666;
        }}
        
        .instructions {{
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 20px;
        }}
        
        .instructions h4 {{
            margin-bottom: 10px;
            color: #856404;
        }}
        
        .instructions ul {{
            margin-left: 20px;
            color: #856404;
        }}
        
        .instructions li {{
            margin-bottom: 5px;
        }}
        
        .legend {{
            background: white;
            padding: 15px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        
        .legend h4 {{
            margin-bottom: 10px;
            color: #333;
        }}
        
        .legend-item {{
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 8px;
        }}
        
        .legend-circle {{
            width: 20px;
            height: 20px;
            border-radius: 50%;
            border: 2px solid #333;
        }}
        
        .legend-circle.red {{
            background: #e74c3c;
        }}
        
        .legend-circle.blue {{
            background: #3498db;
        }}
        
        .legend-circle.marker {{
            background: #95a5a6;
            border: 3px solid #000;
        }}
        
        #map {{
            height: 900px;
            cursor: crosshair;
        }}
        
        .leaflet-popup-content {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }}
        
        button {{
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            width: 100%;
            margin-bottom: 10px;
        }}
        
        button:hover {{
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.2);
        }}
        
        .btn-reset {{
            background: #f44336;
            color: white;
        }}
        
        .btn-random {{
            background: #4CAF50;
            color: white;
        }}
        
        .stats {{
            background: #e3f2fd;
            padding: 10px;
            border-radius: 5px;
            font-size: 0.9em;
            text-align: center;
            margin-top: 15px;
            color: #1565c0;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🗺️ Classification k-NN Interactive</h1>
            <p>Haute-Corse ou Corse du Sud ?</p>
            <div class="stats">
                <strong>{len(villages)}</strong> villages chargés
            </div>
        </div>
        
        <div class="main-content">
            <div class="sidebar">
                <div class="instructions">
                    <h4>📋 Instructions</h4>
                    <ul>
                        <li><strong>Cliquez</strong> n'importe où sur la carte</li>
                        <li>Ajustez la valeur de <strong>k</strong> avec le curseur</li>
                        <li>Observez les <strong>k plus proches villages</strong></li>
                        <li>La <strong>classification</strong> se fait par vote majoritaire</li>
                    </ul>
                </div>
                
                <div class="controls">
                    <h3>⚙️ Paramètres</h3>
                    <div class="control-group">
                        <label>Nombre de voisins (k) :</label>
                        <div class="slider-container">
                            <input type="range" id="kSlider" min="1" max="21" value="5" step="2">
                            <span class="k-value" id="kValue">5</span>
                        </div>
                    </div>
                    <button class="btn-random" onclick="placeRandomPoint()">🎲 Point Aléatoire</button>
                    <button class="btn-reset" onclick="resetClassification()">🔄 Réinitialiser</button>
                </div>
                
                <div class="result-box" id="resultBox">
                    <h3>🎯 Résultat</h3>
                    <div class="prediction no-result" id="prediction">
                        Cliquez sur la carte
                    </div>
                    <div class="coords" id="coords"></div>
                    <div id="votesContainer" style="display: none;">
                        <div class="votes">
                            <div class="vote-item">
                                <div class="vote-count red" id="votes2A">0</div>
                                <div>Corse du Sud</div>
                            </div>
                            <div class="vote-item">
                                <div class="vote-count blue" id="votes2B">0</div>
                                <div>Haute-Corse</div>
                            </div>
                        </div>
                        <h4>🏘️ Plus proches voisins :</h4>
                        <div class="neighbors-list" id="neighborsList"></div>
                    </div>
                </div>
                
                <div class="legend">
                    <h4>Légende</h4>
                    <div class="legend-item">
                        <div class="legend-circle red"></div>
                        <span>Corse du Sud (2A)</span>
                    </div>
                    <div class="legend-item">
                        <div class="legend-circle blue"></div>
                        <span>Haute-Corse (2B)</span>
                    </div>
                    <div class="legend-item">
                        <div class="legend-circle marker"></div>
                        <span>Point à classifier</span>
                    </div>
                </div>
            </div>
            
            <div id="map"></div>
        </div>
    </div>
    
    <!-- Leaflet JS -->
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    
    <script>
        // Données des villages (embarquées depuis le CSV)
        const villages = {villages_json};
        
        let map, testMarker, neighborMarkers = [], neighborLines = [];
        let currentK = 5;
        
        // Initialiser la carte
        function initMap() {{
            map = L.map('map').setView([42.15, 9.05], 9);
            
            L.tileLayer('https://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png', {{
                attribution: '© OpenStreetMap contributors'
            }}).addTo(map);
            
            // Ajouter tous les villages
            villages.forEach(village => {{
                const color = village.dept === '2A' ? '#e74c3c' : '#3498db';
                L.circleMarker([village.lat, village.lon], {{
                    radius: 3,
                    fillColor: color,
                    color: '#333',
                    weight: 1,
                    opacity: 1,
                    fillOpacity: 0.5
                }}).bindPopup(`<b>${{village.name}}</b><br>${{village.nameCorse}}<br>${{village.dept}}`)
                  .addTo(map);
            }});
            
            // Ajouter le gestionnaire de clic
            map.on('click', onMapClick);
        }}
        
        // Calcul de distance Haversine
        function haversineDistance(lat1, lon1, lat2, lon2) {{
            const R = 6371; // Rayon de la Terre en km
            const dLat = (lat2 - lat1) * Math.PI / 180;
            const dLon = (lon2 - lon1) * Math.PI / 180;
            const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                      Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                      Math.sin(dLon/2) * Math.sin(dLon/2);
            const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            return R * c;
        }}
        
        // Classification k-NN
        function knnClassify(lat, lon, k) {{
            // Calculer distances
            const distances = villages.map(village => ({{
                ...village,
                distance: haversineDistance(lat, lon, village.lat, village.lon)
            }}));
            
            // Trier par distance
            distances.sort((a, b) => a.distance - b.distance);
            
            // Prendre les k plus proches
            const neighbors = distances.slice(0, k);
            
            // Voter
            const votes = {{ '2A': 0, '2B': 0 }};
            neighbors.forEach(n => votes[n.dept]++);
            
            const prediction = votes['2A'] > votes['2B'] ? '2A' : '2B';
            
            return {{ prediction, neighbors, votes }};
        }}
        
        // Gestionnaire de clic sur la carte
        function onMapClick(e) {{
            const lat = e.latlng.lat;
            const lon = e.latlng.lng;
            
            classifyPoint(lat, lon);
        }}
        
        // Classifier un point
        function classifyPoint(lat, lon) {{
            // Supprimer les anciens marqueurs
            if (testMarker) map.removeLayer(testMarker);
            neighborMarkers.forEach(m => map.removeLayer(m));
            neighborLines.forEach(l => map.removeLayer(l));
            neighborMarkers = [];
            neighborLines = [];
            
            // Classifier
            const result = knnClassify(lat, lon, currentK);
            
            // Ajouter le marqueur du point test
            testMarker = L.circleMarker([lat, lon], {{
                radius: 12,
                fillColor: '#95a5a6',
                color: '#000',
                weight: 3,
                opacity: 1,
                fillOpacity: 0.8
            }}).addTo(map);
            
            // Ajouter les marqueurs et lignes des voisins
            result.neighbors.forEach(neighbor => {{
                const nColor = neighbor.dept === '2A' ? '#e74c3c' : '#3498db';
                
                // Ligne
                const line = L.polyline(
                    [[lat, lon], [neighbor.lat, neighbor.lon]],
                    {{color: nColor, weight: 2, opacity: 0.5}}
                ).addTo(map);
                neighborLines.push(line);
                
                // Marqueur
                const marker = L.circleMarker([neighbor.lat, neighbor.lon], {{
                    radius: 8,
                    fillColor: nColor,
                    color: '#333',
                    weight: 2,
                    opacity: 1,
                    fillOpacity: 0.8
                }}).bindPopup(`<b>${{neighbor.name}}</b><br>${{neighbor.nameCorse}}<br>${{neighbor.dept}}<br>Distance: ${{neighbor.distance.toFixed(2)}} km`)
                  .addTo(map);
                neighborMarkers.push(marker);
            }});
            
            // Afficher les résultats
            displayResults(lat, lon, result);
        }}
        
        // Afficher les résultats
        function displayResults(lat, lon, result) {{
            const predictionDiv = document.getElementById('prediction');
            const coordsDiv = document.getElementById('coords');
            const votesContainer = document.getElementById('votesContainer');
            const votes2A = document.getElementById('votes2A');
            const votes2B = document.getElementById('votes2B');
            const neighborsList = document.getElementById('neighborsList');
            
            // Coordonnées
            coordsDiv.textContent = `(${{lat.toFixed(4)}}, ${{lon.toFixed(4)}})`;
            
            // Prédiction
            const deptName = result.prediction === '2A' ? 'Corse du Sud (2A)' : 'Haute-Corse (2B)';
            const cssClass = result.prediction === '2A' ? 'corse-sud' : 'haute-corse';
            predictionDiv.textContent = deptName;
            predictionDiv.className = 'prediction ' + cssClass;
            
            // Votes
            votes2A.textContent = result.votes['2A'];
            votes2B.textContent = result.votes['2B'];
            votesContainer.style.display = 'block';
            
            // Liste des voisins
            neighborsList.innerHTML = '';
            result.neighbors.forEach(neighbor => {{
                const div = document.createElement('div');
                div.className = `neighbor-item dept-${{neighbor.dept.toLowerCase()}}`;
                div.innerHTML = `
                    <div class="neighbor-name">${{neighbor.name}} (${{neighbor.dept}})</div>
                    <div class="neighbor-corse">${{neighbor.nameCorse}}</div>
                    <div class="neighbor-distance">Distance: ${{neighbor.distance.toFixed(2)}} km</div>
                `;
                neighborsList.appendChild(div);
            }});
        }}
        
        // Point aléatoire
        function placeRandomPoint() {{
            const lat = 41.3 + Math.random() * (43.0 - 41.3);
            const lon = 8.5 + Math.random() * (9.6 - 8.5);
            classifyPoint(lat, lon);
            map.setView([lat, lon], 10);
        }}
        
        // Réinitialiser
        function resetClassification() {{
            if (testMarker) map.removeLayer(testMarker);
            neighborMarkers.forEach(m => map.removeLayer(m));
            neighborLines.forEach(l => map.removeLayer(l));
            neighborMarkers = [];
            neighborLines = [];
            testMarker = null;
            
            document.getElementById('prediction').textContent = 'Cliquez sur la carte';
            document.getElementById('prediction').className = 'prediction no-result';
            document.getElementById('coords').textContent = '';
            document.getElementById('votesContainer').style.display = 'none';
            
            map.setView([42.15, 9.05], 9);
        }}
        
        // Gestionnaire du slider k
        document.getElementById('kSlider').addEventListener('input', function(e) {{
            currentK = parseInt(e.target.value);
            document.getElementById('kValue').textContent = currentK;
            
            // Reclassifier si un point existe
            if (testMarker) {{
                const latlng = testMarker.getLatLng();
                classifyPoint(latlng.lat, latlng.lng);
            }}
        }});
        
        // Initialisation
        initMap();
    </script>
</body>
</html>'''
    
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(html_content)
    
    print(f"✅ Fichier HTML généré : {output_file}")
    print(f"📊 {len(villages)} villages inclus")

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python generate_interactive_map.py villages_corse.csv")
        sys.exit(1)
    
    csv_file = sys.argv[1]
    villages = load_villages_from_csv(csv_file)
    generate_html(villages)
