import { Loader } from '@googlemaps/js-api-loader';
import { MarkerClusterer } from '@googlemaps/markerclusterer';
import { gmapStyles } from './gmap/styles';

let gmapsLoaded = false;

let map;
let zoom = window.innerWidth > 2300 ? 8 : window.innerWidth > 768 ? 7 : 6;
const singleMarkerZoom = 16;
let lat = 49.9501319;
let lng = 15.2541319;
let activeInfoWindow;
let fitBounds;

const createMap = (mapElement) => {
    const markerElements = mapElement.querySelectorAll('.gmap-marker');
    const zoomAttr = mapElement.getAttribute('data-zoom');
    const latAttr = mapElement.getAttribute('data-lat');
    const lngAttr = mapElement.getAttribute('data-lng');
    fitBounds = mapElement.getAttribute('data-fit') ?? false;

    zoom = zoomAttr ? parseInt(zoomAttr) : zoom;
    lat = latAttr ? parseFloat(latAttr) : lat;
    lng = lngAttr ? parseFloat(lngAttr) : lng;

    const args = {
        zoom: zoom,
        center: new google.maps.LatLng(lat, lng),
        draggable: true,
        scrollwheel: false,
        disableDoubleClickZoom: true,
        panControl: false,
        zoomControl: true,
        scaleControl: false,
        mapTypeControl: false,
        streetViewControl: false,
        overviewMapControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    /* Create map */

    map = new google.maps.Map(mapElement, args);

    map.markers = [];

    const styledMapOptions = {
        map: map
    };

    const mainmap = new google.maps.StyledMapType(gmapStyles, styledMapOptions);

    map.mapTypes.set('site_map', mainmap);
    map.setMapTypeId('site_map');

    /* Add markers */
    const markers = [];
    for (const markerEl of markerElements) {
        const marker = addMarker(markerEl, map, (fitBounds || markerElements.length === 1));
        markers.push(marker);
    }

    clusterMarkers(map, markers);

    if (fitBounds || markerElements.length === 1) {
        centerMap(map);

        window.addEventListener('resize', () => {
            centerMap(map);
        });
    }

    return map;
}

const clusterMarkers = (map, markers) => {
    const image = {
        url: '/static/images/cluster.svg',
        size: new google.maps.Size(34, 34),
        scaledSize: new google.maps.Size(34, 34),
        origin: new google.maps.Point(0, 0),
        anchor: new google.maps.Point(17, 34)
    };

    const renderer = {
        render: ({ count, position }) =>
            new google.maps.Marker({
                label: { text: String(count), color: 'white', fontSize: '15px', fontWeight: '600', fontFamily: 'Open Sans' },
                position,
                icon: image,
                zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count
            })
    };

    const clusterer = new MarkerClusterer({ map, markers, renderer });
    return clusterer;
}

const addMarker = (markerElement, map, bigMarker = false) => {
    const id = markerElement.getAttribute('id');
    let dataLat = markerElement.getAttribute('data-lat');
    let dataLng = markerElement.getAttribute('data-lng');

    dataLat = dataLat.replace(',', '.');
    dataLng = dataLng.replace(',', '.');

    const latlng = new google.maps.LatLng(dataLat, dataLng);

    let pin = markerElement.getAttribute('data-marker');
    if (!pin) {
        pin = bigMarker ? '/static/images/marker-big.svg' : '/static/images/marker.svg';
    }

    const width = bigMarker ? 28 : 28;
    const height = bigMarker ? 36 : 36;
    const image = {
        url: pin,
        size: new google.maps.Size(width, height),
        scaledSize: new google.maps.Size(width, height),
        origin: new google.maps.Point(0, 0),
        anchor: new google.maps.Point(width / 2, height)
    };

    const markerAttributes = {
        id: id,
        position: latlng,
        map: map,
        icon: image
    };

    if (markerElement.classList.contains('highlighted')) {
        markerAttributes.zIndex = 999;
    }

    const marker = new google.maps.Marker(markerAttributes);
    const clickable = markerElement.getAttribute('data-clickable') ?? true;

    map.markers.push(marker);

    if (markerElement.innerHTML) {
        const infowindow = new google.maps.InfoWindow({
            content: markerElement.innerHTML
        });

        if (clickable) {
            google.maps.event.addListener(marker, 'click', () => {
                if (activeInfoWindow) {
                    activeInfoWindow.close();
                }
                infowindow.open(map, marker);
                activeInfoWindow = infowindow;
            });
        }
    }

    return marker;
}

const centerMap = (map) => {
    const bounds = new google.maps.LatLngBounds();
    const offsetX = 0;

    for (const marker of map.markers) {
        const latlng = new google.maps.LatLng(
            marker.position.lat(),
            marker.position.lng() - offsetX
        );
        bounds.extend(latlng);
    }

    if (map.markers.length === 1) {
        map.setCenter(bounds.getCenter());
        map.setZoom(singleMarkerZoom);
    } else if (fitBounds) {
        map.fitBounds(bounds);
    }
}

const initMaps = () => {
    const maps = document.querySelectorAll('.gmap');
    for (const mapEl of maps) {
        const options = {
            root: null,
            rootMargin: '0px',
            threshold: 0.5
        };

        const observer = new IntersectionObserver((entries) => {
            for (const entry of entries) {
                if (entry.isIntersecting) {
                    mapInViewport(entry.target);
                }
            }
        }, options);

        observer.observe(mapEl);
    }
};

const mapInViewport = (mapEl) => {
    if (mapEl.classList.contains('map--active')) {
        return;
    }

    if (!gmapsLoaded) {
        const loader = new Loader({
            apiKey: 'AIzaSyDsBZCDolAdLiHsb65bk7USBSxVAVILWBM',
            version: 'weekly',
            libraries: []
        });
        loader.load()
            .then(() => {
                gmapsLoaded = true;
                initMap(mapEl);
            })
            .catch((e) => {});
    } else {
        initMap(mapEl);
    }
}

const initMap = (mapEl) => {
    map = createMap(mapEl);
    console.log('init');
    mapEl.classList.add('map--active');
}

export { initMaps };
