/**

Contrôleur qui gère la carte (charge son contenu et contrôle l’interactivité)

Voir la macro Twig `map` qui produit le HTML géré par ce contrôleur.

Cf <https://leafletjs.com/reference.html>

**/
import { Controller } from '@hotwired/stimulus';
import 'leaflet';
import 'leaflet.markercluster';

export default class extends Controller {
    static targets = [ 'openLink' ];
    static values = {
        geojson: String,
        overpassResult: String,
        icon: String,
        popupUrl: String,
    }

    connect() {
        const self = this;

        // Constitue une collection d’icones aux couleurs Bootstrap
        const iconHtml = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="bi bi-geo-alt-fill" viewBox="0 0 16 16">
  <path fill="currentColor" d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6"/>
</svg>
            `; 
        const icons = {
            'danger': L.divIcon({ html: iconHtml, className: 'svg-icon text-danger', iconSize: [16, 16], iconAnchor: [8, 16], }),
            'warning': L.divIcon({ html: iconHtml, className: 'svg-icon text-warning', iconSize: [16, 16], iconAnchor: [8, 16], }),
            'success': L.divIcon({ html: iconHtml, className: 'svg-icon text-success', iconSize: [16, 16], iconAnchor: [8, 16], }),
            'info': L.divIcon({ html: iconHtml, className: 'svg-icon text-info', iconSize: [16, 16], iconAnchor: [8, 16], }),
        };

        var geojsons, _this = this, map = L.map(this.element.querySelector('#map'));
        this.mapInstance = map;

        // Commence par déclarer le fond de carte classique OSM par défaut
        L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 19,
            attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
        }).addTo(map);

        // Suit les mouvements de la carte
        map.on('moveend', function() {
            var center = map.getCenter();
            var lat = center.lat;
            var lng = center.lng;
            self.openLinkTarget.setAttribute('href', `geo:${lat},${lng}`);
        });

        // Crée un ensemble de couches pour mieux les manipuler
        // individuellement
        var layer = L.featureGroup();

        // Crée la couche dédiée à Overpass
        var overpassLayer = L.markerClusterGroup();
        if (this.overpassResultValue !== '') {
            geojsons = JSON.parse(this.overpassResultValue);
            if (geojsons.elements.length > 0) {
                // Ajoute chaque forme
                geojsons.elements.forEach(function (element) {
                    // Cas d’un nœud
                    if (element.type === 'node') {
                        L.marker([ element.lat, element.lon ], {
                            icon: icons['info'],
                        }).addTo(overpassLayer).bindPopup(L.popup({
                            overpassElement: element, // on transmet les données du geojson à la popup par là
                        }).setContent('…')); // le contenu définitif de la popup sera chargé plus tard en ajax
                    }
                    // Cas d’autre chose qu’un nœud, sans distinction
                    if (element.members) {
                        element.members.forEach(function (member) {
                            // TODO On est parti du principe que les features du
                            // geojson sont toutes des polylines ce qui est un peu
                            // réducteur, à terme il faudrait distinguer les géométries
                            const polygon = L.polyline(member.geometry.map(function (coord) { return L.latLng(coord.lat, coord.lon)}), {
                                color:  '#0dcaf0', // bleu info bootstrap
                                weight: 6, // l’idée c’est que ce soit plus gros (par défaut c’est 3) que le tracé des données des tâches parce que ce sera en dessous
                                opacity: 0.8,
                            }).addTo(overpassLayer).bindPopup(L.popup({
                                overpassElement: element, // on transmet les données du geojson à la popup par là
                            }).setContent('…')); // le contenu définitif de la popup sera chargé plus tard en ajax
                        });
                    }
                });
                // Intervient lors de l’ouverture de la popup associée à la forme
                overpassLayer.on('popupopen', function (event) {
                    // Récupère le geojson de la forme
                    var element = event.popup.options.overpassElement;
                    // Enlève ce qui nous est inutile (les points, etc)
                    delete element.members;
                    // Ajoute ce qui peut-être utile (concernant la carte0
                    element['map'] = {
                        'center': map.getCenter(),
                        'zoom': map.getZoom(),
                    };
                    // Effectue l’appel ajax pour récupérer le contenu de la popup
                    fetch(_this.popupUrlValue + '?' + (new URLSearchParams({
                        'element': JSON.stringify(element),
                    })))
                        .then(function (response) {
                            return response.text();
                        })
                        .then(function (text) {
                            event.popup.setContent(text);
                        });
                });
                overpassLayer.addTo(layer);
            }
        }

        // Créé la couche dédiée aux tâches
        var taskLayer = L.featureGroup();
        geojsons = JSON.parse(this.geojsonValue);
        if (geojsons.length > 0) {
            geojsons.forEach(function (geojson) {
                geojson.features.forEach(function (feature) {
                    // Dessine la forme de la tâche avec la proprieté `name` qui
                    // s’ffiche au survol et cliquable vers l’adresse web dans la
                    // propriété `url`
                    if (feature.geometry.type === 'Point') {
                        L.marker([
                            feature.geometry.coordinates[1],
                            feature.geometry.coordinates[0],
                        ], {
                            icon: icons[feature.properties.color],
                            title: feature.properties.name,
                            clickUrl: feature.properties.url,
                        }).addTo(taskLayer).on('click', function (event) {
                            window.location.href = event.target.options.clickUrl;
                        });
                    } else {
                        const polygon = L.geoJSON(feature, {
                            style: function (feature) {
                                // Par défaut c’est un bleu par défaut de leaflet mais
                                // sinon on utilise les couleurs de Bootstrap
                                var color = 'blue';
                                switch (feature.properties.color) {
                                    case 'danger' : color = '#dc3545'; break
                                    case 'warning' : color = '#ffc107'; break
                                    case 'success' : color = '#198754'; break
                                }
                                if (feature.geometry.type === 'Polygon') {
                                    return {
                                        color: color,
                                        weight: 1,
                                        fillOpacity: 0.5,
                                    };
                                } else {
                                    return {color: color};
                                }
                            }
                        }).bindTooltip(feature.properties.name).addTo(taskLayer).on('click', function (event) {
                            window.location.href = event.layer.feature.properties.url;
                        });
                    }
                });
            });
            taskLayer.addTo(layer);
        }

        layer.addTo(map);

        // Si la couche Overpass n’est pas vide, ajoute le sélecteur de couches
        // sur la carte
        if (this.overpassResultValue !== '') {
            L.control.layers({}, {
                'Overpass': overpassLayer,
                'Tâches': taskLayer,
            }).addTo(map);
        }

        // Zoome la carte pour que les données des tâches soient toutes
        // visibles
	try {
            map.fitBounds(taskLayer.getBounds());
	} catch (error) {} // TODO gérer l'erreur plus proprement quand il n'y a pas de GeoJSON
    }

    openInOsm() {
        const url = "https://www.openstreetmap.org/#map="+this.mapInstance.getZoom()+"/"+this.mapInstance.getCenter().lat+"/"+this.mapInstance.getCenter().lng;
        window.open(url, '_blank');
    }

    openInPanoramax() {
        const url = "https://api.panoramax.xyz/#focus=map&map="+this.mapInstance.getZoom()+"/"+this.mapInstance.getCenter().lat+"/"+this.mapInstance.getCenter().lng;
        window.open(url, '_blank');
    }

    openInPifomap() {
        const self = this, url1 = "https://geo.api.gouv.fr/communes?lat="+this.mapInstance.getCenter().lat+"&lon="+this.mapInstance.getCenter().lng+"&fields=code,nom";
        fetch(url1).then(function (response) { return response.json(); }).then(function (json) {
            const hasInsee = (Array.isArray(json) && (json.length > 0) && json[0].hasOwnProperty('code'));
            if (hasInsee) {
                const url2 = "https://bano.openstreetmap.fr/pifometre/pifomap.html?insee="+json[0].code;
                window.open(url2, '_blank');
            } else {
                window.alert('Impossible de trouver le code INSEE de la commune…');
            }
        });
    }

    openInPifometre() {
        const self = this, url1 = "https://geo.api.gouv.fr/communes?lat="+this.mapInstance.getCenter().lat+"&lon="+this.mapInstance.getCenter().lng+"&fields=code,nom";
        fetch(url1).then(function (response) { return response.json(); }).then(function (json) {
            const hasInsee = (Array.isArray(json) && (json.length > 0) && json[0].hasOwnProperty('code'));
            if (hasInsee) {
                const url2 = "https://bano.openstreetmap.fr/pifometre/?insee="+json[0].code;
                window.open(url2, '_blank');
            } else {
                window.alert('Impossible de trouver le code INSEE de la commune…');
            }
        });
    }

    openInGeohack() {
        const url = "https://geohack.toolforge.org/geohack.php?params="+this.mapInstance.getCenter().lat+"_N_"+this.mapInstance.getCenter().lng+"_E";
        window.open(url, '_blank');
    }

    openInGeoportail() {
        const url = "https://www.geoportail.gouv.fr/carte?c="+this.mapInstance.getCenter().lng+","+this.mapInstance.getCenter().lat+"&z="+this.mapInstance.getZoom()+"&permalink=yes";
        window.open(url, '_blank');
    }

    openInMapillary() {
        const url = "https://www.mapillary.com/app/?lat="+this.mapInstance.getCenter().lat+"&lng="+this.mapInstance.getCenter().lng+"&z="+this.mapInstance.getZoom();
        window.open(url, '_blank');
    }

    openInGoogleMaps() {
        const url = "https://www.google.com/maps/@"+this.mapInstance.getCenter().lat+","+this.mapInstance.getCenter().lng+","+this.mapInstance.getZoom()+"z";
        window.open(url, '_blank');
    }

    openInBing() {
        const url = "https://www.bing.com/maps/?cp="+this.mapInstance.getCenter().lat+"%7E"+this.mapInstance.getCenter().lng+"&lvl="+this.mapInstance.getZoom();
        window.open(url, '_blank');
    }

    openInF4Map() {
        const url = "https://demo.f4map.com/#lat="+this.mapInstance.getCenter().lat+"&lon="+this.mapInstance.getCenter().lng+"&zoom="+this.mapInstance.getZoom();
        window.open(url, '_blank');
    }

}
