import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useContext, useRef, useState, useEffect, forwardRef } from 'react';
import styled, { css } from 'styled-components';
import { defaultThemeProp } from '../../theme';
import Progress from '../Progress';
import { Status } from '../Badges';
import { createUID } from '../../utils';
import useTheme from '../../hooks/useTheme';
import { omitProps } from '../../styles';
import { loadMapsAPI, toGoogleLatLng, getPlaceById, isLatLngObject, getAddress } from './utils';
import MapsContext from './MapsContext';
export const StyledLocationError = styled(Status) `
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
`;
StyledLocationError.defaultProps = defaultThemeProp;
export const StyledLocationView = styled.div.withConfig(omitProps('height'))(({ height, theme }) => {
    return css `
      min-height: inherit;
      height: ${height};
      position: relative;
      flex: auto;
      border-radius: ${theme.base['border-radius']};
      mask-image: radial-gradient(white, black);
      -webkit-mask-image: radial-gradient(white, black);
    `;
});
StyledLocationView.defaultProps = defaultThemeProp;
const StyledMap = styled.div(({ disabled, status, theme: { base: { 'disabled-opacity': disabledOpacity } } }) => {
    return css `
      position: absolute;
      inset: 0;
      ${disabled &&
        css `
        opacity: ${disabledOpacity};
      `}
      ${status === 'error' &&
        css `
        opacity: ${disabledOpacity};
      `}
    `;
});
StyledMap.defaultProps = defaultThemeProp;
var LoadStatus;
(function (LoadStatus) {
    LoadStatus["Init"] = "init";
    LoadStatus["Ready"] = "ready";
    LoadStatus["Error"] = "error";
})(LoadStatus || (LoadStatus = {}));
const hasPlaceId = (obj) => {
    return typeof obj === 'object' && obj.placeId && typeof obj.placeId === 'string';
};
/* cSpell:ignore 'ABCDEFGHIJKLMNOPQRSTUVWYZ' */
const markerLabels = 'ABCDEFGHIJKLMNOPQRSTUVWYZ';
const LocationView = forwardRef(function LocationView(props, ref) {
    const { pins = [], zoomLevel = 13, height = '25rem', centerMapOnChange = false, onClick, onError, disabled = false, loading = false, drawRoute = false, ...restProps } = props;
    const { name, ...providerOpts } = useContext(MapsContext);
    const [status, setStatus] = useState(LoadStatus.Init);
    const [eMessage, setEMessage] = useState('');
    const mapElemRef = useRef();
    const map = useRef();
    const markers = useRef([]);
    const ds = useRef();
    const dr = useRef();
    const theme = useTheme();
    const onMapClick = (e) => {
        if (!isLatLngObject(e.latLng))
            return;
        if (hasPlaceId(e)) {
            getPlaceById(e.placeId).then(placeInfo => {
                onClick?.({
                    ...placeInfo,
                    latitude: e.latLng.lat(),
                    longitude: e.latLng.lng()
                });
            });
        }
        else {
            getAddress({
                latitude: e.latLng.lat(),
                longitude: e.latLng.lng()
            })
                .then(onClick)
                .catch(err => onError?.(err));
        }
    };
    const initialize = () => {
        if (mapElemRef.current) {
            const position = toGoogleLatLng({ latitude: 0, longitude: 0 });
            map.current = new google.maps.Map(mapElemRef.current, {
                mapId: createUID(),
                center: position,
                zoom: 2,
                draggable: !disabled,
                draggableCursor: 'auto',
                draggingCursor: 'move'
            });
            ds.current = new google.maps.DirectionsService();
            dr.current = new google.maps.DirectionsRenderer({ suppressMarkers: true });
        }
    };
    useEffect(() => {
        if (!onClick || !map.current)
            return;
        const l = map.current.addListener('click', onMapClick);
        return () => google.maps.event.removeListener(l);
    }, [onClick, map.current]);
    useEffect(() => {
        let mounted = true;
        loadMapsAPI(name, providerOpts)
            .then(() => {
            if (mounted) {
                initialize();
                setStatus(LoadStatus.Ready);
            }
        })
            .catch((error) => {
            setStatus(LoadStatus.Error);
            setEMessage(error.message);
            onError?.(error);
        });
        return () => {
            mounted = false;
            if (map.current)
                google.maps.event.clearInstanceListeners(map.current);
        };
    }, []);
    useEffect(() => {
        if (status !== LoadStatus.Ready ||
            !map.current ||
            !dr.current ||
            !ds.current ||
            // FIXME: Workaround for marker library not being imported
            !google.maps.marker)
            return;
        if (drawRoute && pins.length > 1) {
            dr.current.setMap(map.current);
            const request = {
                origin: toGoogleLatLng({ latitude: pins[0].latitude, longitude: pins[0].longitude }),
                destination: toGoogleLatLng({
                    latitude: pins[pins.length - 1].latitude,
                    longitude: pins[pins.length - 1].longitude
                }),
                waypoints: pins.slice(1, pins.length - 1).map(l => {
                    return {
                        stopover: true,
                        location: toGoogleLatLng({
                            latitude: l.latitude,
                            longitude: l.longitude
                        })
                    };
                }),
                travelMode: google.maps.TravelMode.DRIVING
            };
            ds.current.route(request).then(dr.current.setDirections.bind(dr.current), onError);
        }
        const bounds = new google.maps.LatLngBounds();
        markers.current = pins.map(({ latitude, longitude, title, selected }, index) => {
            const gCoords = toGoogleLatLng({ latitude, longitude });
            const contentConfig = {
                glyphColor: theme.base.colors.white
            };
            if (pins.length > 1) {
                const glyphWrapper = document.createElement('span');
                glyphWrapper.style.fontSize = '0.9rem';
                glyphWrapper.style.paddingTop = '0.1rem';
                glyphWrapper.innerHTML = markerLabels[index % markerLabels.length];
                contentConfig.glyph = glyphWrapper;
            }
            if (selected) {
                contentConfig.background = theme.base.colors.red.dark;
                contentConfig.borderColor = theme.base.colors.red.dark;
                contentConfig.scale = 1.15;
            }
            const content = new google.maps.marker.PinElement(contentConfig);
            const marker = new google.maps.marker.AdvancedMarkerElement({
                map: map.current,
                position: gCoords,
                title,
                content: content.element
            });
            bounds.extend(gCoords);
            return marker;
        });
        if (centerMapOnChange) {
            if (pins.length === 1) {
                map.current.setCenter(toGoogleLatLng(pins[0]));
                map.current.setZoom(zoomLevel);
            }
            else if (pins.length > 1) {
                map.current.fitBounds(bounds);
            }
        }
        return () => {
            markers.current.forEach(m => {
                m.map = null;
            });
            dr.current?.setMap(null);
        };
    }, [JSON.stringify(pins), status, zoomLevel, disabled, drawRoute, centerMapOnChange, onError]);
    return (_jsxs(StyledLocationView, { height: height, ref: ref, children: [_jsx(StyledMap, { ref: mapElemRef, disabled: disabled, status: status, ...restProps }), (status === LoadStatus.Init || loading) && _jsx(Progress, { placement: 'local' }), status === LoadStatus.Error && eMessage && (_jsx(StyledLocationError, { "aria-label": eMessage, variant: 'info', children: eMessage }))] }));
});
export default LocationView;
//# sourceMappingURL=LocationView.js.map