import React, { memo, useState, useRef, useEffect, useContext } from "react";
import GoogleMapReact from "google-map-react";
import useSupercluster from "use-supercluster";
import ReactTooltip from "react-tooltip";
import ReactDOM from 'react-dom';
import { ThemeContext } from 'styled-components';

import { GMAP_KEY } from "~/utils/constants";
import { Circle } from "~/components";
import { Marker } from "~/components";
import BrAll from "~assets/data/brazil-map.json";
import * as Styled from "./styles.js";
import { Chips } from "~/components";

const suspect = [];
const recovered = [];

const MapArea = ({ userLat, userLng, initialZoom, citiesCases, error }) => {

    const themeContext = useContext(ThemeContext);

    const defaultOptions = {
				zoom: initialZoom,
				gestureHandling: 'greedy',
        /*limites mapa*/
        southAmericaBounds: {
            west: -103.8386805338,
            south: -43.054008204,
            east: -15.3869376826,
            north: 16.2780526563,
        },
    }

    const mapRef = useRef();
    const mapsRef = useRef();
    const [zoom, setZoom] = useState(defaultOptions.zoom);
    const [bounds, setBounds] = useState(null);
    const [markersHospital, setMarkersHospital] = useState([]);
    const [circleSize, setCircleSize] = useState(80);

    const getCityCases = () => {
        let cityCases = [];

        citiesCases.map(cases => {
            if (cases.ibge_id && cityCases.indexOf(cases.ibge_id) === -1) {
                cityCases.push(cases);
            }
        });

        return cityCases;
    }

    const getCasesCity = () => {
        let cityCases = [];

        const _getCityCases = getCityCases();
        const cityProp = BrAll.objects.BR_LEVE.geometries;

        _getCityCases.map(city => {
            for (let _key in cityProp) {
                if (city.ibge_id === cityProp[_key].properties.id) {
                    let { id, centroide, NM_MUNICIP: cityName } = cityProp[
                        _key
                    ].properties;

                    centroide = centroideFormat(centroide);
                    cityCases.push({
                        id,
                        cityName,
                        totalCases: city.totalcases,
                        longitude: centroide[0],
                        latitude: centroide[1]
                    });
                }
            }
        });

        return cityCases;
    }

    const centroideFormat = value => {
        return value
            .replace("(", "")
            .replace(")", "")
            .split(",");
    }

    let confirmed = getCasesCity()

    confirmed.map(item => {
        item['type'] = 'confirmed'
    })

    const markers = [...confirmed, ...suspect, ...recovered]

    const points = markers.map((marker, index) => ({
        type: "Feature",
        properties: { cluster: false, category: marker.type, id: index, totalCases: marker.totalCases, cityName: marker.cityName },
        geometry: {
            type: "Point",
            coordinates: [
                marker.longitude,
                marker.latitude
            ]
        }
    }))

    const { clusters, supercluster } = useSupercluster({
        points,
        bounds,
        zoom,
        options: { radius: 150, maxZoom: 20 }
    });
    

    const createRoute = (map, maps, placeId) => {

        var directionsService = new maps.DirectionsService();
        var directionsRenderer = new maps.DirectionsRenderer();
        directionsRenderer.setMap(map);

        let origin = new maps.LatLng(userLat, userLng);

        directionsService.route(
            {
                origin,
                destination: { placeId },
                travelMode: 'DRIVING'
            },
            function (response, status) {
                if (status === 'OK') {
                    directionsRenderer.setDirections(response);
                } else {
                    window.alert('Directions request failed due to ' + status);
                }
            });

    }

    const getHospitals = () => {

        const map = mapRef.current;
        const maps = mapsRef.current;

        if (!map || !maps) return
        //let bounds = map.getBounds()

        let pyrmont = new maps.LatLng(map.getCenter().lat(), map.getCenter().lng());
        let places = new maps.places.PlacesService(map);

        var request = {
            location: pyrmont,
            //bounds,
            radius: '5000',
            type: ['hospital'],
        };

        places.nearbySearch(
            request,
            function (results, status, pagination) {
                if (status !== 'OK') return;
                setMarkersHospital(results)
            });

    }

    useEffect(() => {
        if (zoom <= 10) {
            setMarkersHospital([])
        } else {
            getHospitals();
        }

        let minPixelSize = 80;
        let maxPixelSize = 350;

        let relativePixelSize = Math.round(Math.pow(zoom, 2.1));

        if (relativePixelSize > maxPixelSize)
            relativePixelSize = maxPixelSize;

        if (relativePixelSize < minPixelSize)
            relativePixelSize = minPixelSize;

        setCircleSize(relativePixelSize)

    }, [bounds, zoom]);

    const isOpen = async (placeId) => {

        const maps = mapsRef.current
        const map = mapRef.current

        let request = {
            placeId,
        }

        let places = new maps.places.PlacesService(map);

        let isOpen = await places.getDetails(request, (place, status) => {
            if (status === maps.places.PlacesServiceStatus.OK) {
                return (place.opening_hours && place.opening_hours.isOpen())
            } else {
                return false
            }
        });

        return isOpen

    }

    const _onChange = ({ zoom, bounds }) => {
        setZoom(zoom);
        setBounds([
            bounds.nw.lng,
            bounds.se.lat,
            bounds.se.lng,
            bounds.nw.lat
        ])
    }

    const _youClick = () => {
        const map = mapRef.current
        map.setZoom(14);
        map.panTo({ lat: userLat, lng: userLng })
    }

    const _apiIsLoaded = (map, maps) => {
        mapRef.current = map;
        mapsRef.current = maps;
        getHospitals()
        //createRoute(map, maps, 'ChIJC_-xjJ-QyJQR1yqVAokq4GY')

        /* */
        const legendsDiv = document.createElement('div');
        ReactDOM.render(
            <Styled.ContainerChips>
                <Chips height={10} onClick={_youClick} theme={themeContext} text="VocĂȘ" type="you" />
                <Chips height={10} theme={themeContext} text="Confirmados" type="confirmed" />
            </Styled.ContainerChips>
            , legendsDiv);
        map.controls[maps.ControlPosition.BOTTOM_CENTER].push(legendsDiv);
        /**/

    };

    const _createMapOptions = (maps) => {
        // next props are exposed at maps
        // "Animation", "ControlPosition", "MapTypeControlStyle", "MapTypeId",
        // "NavigationControlStyle", "ScaleControlStyle", "StrokePosition", "SymbolPath", "ZoomControlStyle",
        // "DirectionsStatus", "DirectionsTravelMode", "DirectionsUnitSystem", "DistanceMatrixStatus",
        // "DistanceMatrixElementStatus", "ElevationStatus", "GeocoderLocationType", "GeocoderStatus", "KmlLayerStatus",
        // "MaxZoomStatus", "StreetViewStatus", "TransitMode", "TransitRoutePreference", "TravelMode", "UnitSystem"
        return {
            zoomControlOptions: {
                position: maps.ControlPosition.RIGHT_BOTTOM,
                style: maps.ZoomControlStyle.SMALL
            },
            mapTypeControlOptions: {
                position: maps.ControlPosition.TOP_RIGHT
            },
            mapTypeControl: true,
            fullscreenControl: false,
            restriction: {
                latLngBounds: defaultOptions.southAmericaBounds,
                strictBounds: false
            },
            minZoom: 4,
            maxZoom: 16
        };
    }

    const _onChildClick = () => {
        
    }

    return (
        <GoogleMapReact
            bootstrapURLKeys={{ key: GMAP_KEY, libraries: ['places'] }}
            defaultCenter={[userLat, userLng]}
            defaultZoom={defaultOptions.zoom}
            yesIWantToUseGoogleMapApiInternals
            onGoogleApiLoaded={({ map, maps }) => _apiIsLoaded(map, maps)}
            onChange={_onChange}
            options={_createMapOptions}
            onChildClick={_onChildClick}
        >

            {clusters.map(cluster => {
                const [longitude, latitude] = cluster.geometry.coordinates;
                const { cluster: isCluster, point_count: pointCount, category, id, cityName, totalCases } = cluster.properties

                if (isCluster) {
                    return (
                        <Circle key={cluster.id} width={circleSize} height={circleSize} isCluster={isCluster} pointCount={pointCount} type="confirmed"
                            lat={latitude}
                            lng={longitude}
                            onClick={() => {
                                const expansionZoom = Math.min(
                                    supercluster.getClusterExpansionZoom(cluster.id), 20
                                );
                                mapRef.current.setZoom(expansionZoom);
                                mapRef.current.panTo({ lat: latitude, lng: longitude })
                            }}
                        />
                    )
                }

                return (

                    <Styled.ContainerMarker
                        lat={latitude}
                        lng={longitude}
                        key={id}
                        data-tip={`
                        <strong>Cidade:</strong> ${cityName} <br>
                        <strong>Casos:</strong> ${totalCases} <br>
                        `}
                    >
                        <Circle width={circleSize} height={circleSize} type={category} />
                        <ReactTooltip html={true} />
                    </Styled.ContainerMarker>

                )

            })}

            {userLat && userLng && !error &&
                <Styled.ContainerMarker
                    lat={userLat}
                    lng={userLng}
                    key={-1}
                    data-tip='VocĂȘ'
                >
                    <Circle type='you' />
                    <ReactTooltip />
                </Styled.ContainerMarker>
            }

            {markersHospital.map((hospital) => {
                const { lat, lng } = hospital.geometry.location;
                return (
                    <Styled.ContainerMarker
                        lat={lat()}
                        lng={lng()}
                        key={hospital.id}
                        data-tip={`
                        ${hospital.name} </br>
                        ${hospital.opening_hours && hospital.opening_hours.open_now ? "Aberto" : ''} <!-- deprecated -->
                        `}
                    >
                        <Marker type='hospital' />
                        <ReactTooltip html={true} />
                    </Styled.ContainerMarker>

                )
            })}

        </GoogleMapReact>
    );
}

export default memo(MapArea);