import leaflet from 'leaflet';
import { useEffect, useRef } from 'preact/hooks';
import { MapProps } from './types';

import 'leaflet/dist/leaflet.css';

export const MapComponent = ({ markers, onMapClick }: MapProps) => {
    const mapContainerRef = useRef<HTMLDivElement>(null);
    const mapRef = useRef<leaflet.Map | undefined>(undefined);

    useEffect(() => {
        if (mapRef.current) {
            return;
        }

        if (!mapContainerRef.current) {
            return;
        }

        const map = leaflet.map(mapContainerRef.current);
        map.setView([47.42111, 10.98528], 13);

        leaflet
            .tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
                maxZoom: 19,
                attribution:
                    '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
            })
            .addTo(map);

        mapRef.current = map;

        return () => {
            map.remove();
        };
    }, []);

    useEffect(() => {
        const map = mapRef.current;
        if (!map) {
            return;
        }

        const handler: leaflet.LeafletMouseEventHandlerFn = ({ latlng }) =>
            onMapClick(latlng);
        map.on('click', handler);

        return () => {
            map.removeEventListener('click', handler);
        };
    }, [mapRef, onMapClick]);

    useEffect(() => {
        const map = mapRef.current;
        if (!map) {
            return;
        }

        const layers: leaflet.Layer[] = [];
        for (let i = 0; i < markers.length; i++) {
            const thisMarker = markers[i];
            const previousMarker = markers[i - 1];
            if (thisMarker && previousMarker) {
                layers.push(
                    leaflet.polyline([
                        previousMarker.coordinates,
                        thisMarker.coordinates,
                    ]),
                );
            }
        }

        layers.push(
            ...markers.flatMap((marker) => {
                const circle = leaflet.circleMarker(marker.coordinates, {
                    bubblingMouseEvents: false,
                    color: 'black',
                    fill: true,
                    fillOpacity: 100,
                    radius: 10,
                });
                const tooltip = leaflet
                    .tooltip(
                        {
                            permanent: true,
                            direction: 'center',
                            className: 'text',
                            content: marker.label,
                        },
                        circle,
                    )
                    .setLatLng(marker.coordinates);

                circle.on('click', marker.remove);
                return [circle, tooltip];
            }),
        );

        for (const layer of layers) {
            layer.addTo(map);
        }

        return () => {
            for (const layer of layers) {
                layer.removeFrom(map);
                layer.remove();
            }
        };
    }, [mapRef, markers]);

    return <div ref={mapContainerRef} class="map-container" />;
};
