import { Ref, useState } from 'react';
import { createPortal } from 'react-dom';
import { MapContainer, MapContainerProps, TileLayer, TileLayerProps } from 'react-leaflet';
import clsx from 'clsx';
import { LatLngLiteral, Map } from 'leaflet';

import useDefaultProps from '../../../hooks/useDefaultProps';
import Controls, { IControlsProps } from '../shared/Controls';
import MapWrapper, { MapWrapperProps } from '../shared/MapWrapper';
import StaticMarker, { StaticMarkerProps } from '../shared/StaticMarker';

export type LocationViewProps = {
	position: LatLngLiteral;
	ref?: Ref<Map>;

	slotProps?: {
		mapWrapper?: MapWrapperProps;
		tileLayer?: TileLayerProps;
		marker?: Omit<StaticMarkerProps, 'position'>;
		controls?: Omit<IControlsProps, 'onChange'>;
	};
} & Omit<MapContainerProps, 'children' | 'center'>;

const LocationView = (inProps: LocationViewProps) => {
	const {
		position,
		ref,
		zoom = 17,
		slotProps,
		className,
		...mapContainer
	} = useDefaultProps({
		name: 'ReevolveLocationView',
		props: inProps
	});

	const [rootElement, setRootElement] = useState<HTMLDivElement | null>(null);

	return (
		<MapWrapper
			{...slotProps?.mapWrapper}
			ref={(_rootElement) => setRootElement(_rootElement)}
		>
			<MapContainer
				fadeAnimation
				zoomAnimation
				markerZoomAnimation
				attributionControl={false}
				zoomControl={false}
				doubleClickZoom
				trackResize
				touchZoom
				boxZoom
				preferCanvas
				bounceAtZoomLimits
				tapHold
				maxZoom={18}
				minZoom={0}
				dragging={true}
				scrollWheelZoom={true}
				{...mapContainer}
				center={position}
				zoom={zoom}
				ref={ref}
				className={clsx('map-container', className)}
			>
				<TileLayer
					attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
					url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
					{...slotProps?.tileLayer}
				/>

				<StaticMarker
					{...slotProps?.marker}
					position={position}
				/>

				{rootElement && createPortal(<Controls {...slotProps?.controls} />, rootElement)}
			</MapContainer>
		</MapWrapper>
	);
};

declare module '@mui/material' {
	interface Components {
		ReevolveLocationView?: {
			defaultProps?: Partial<LocationViewProps>;
		};
	}
}

export default LocationView;
