<script lang="ts">
	import { onMount, onDestroy, type Snippet } from 'svelte';
	import type { IMap } from './core';
	import type { LngLatTuple } from '$domain';
	import { createMapLibreMap } from './maplibre';
	import { setMapContext } from './context';

	interface Props {
		center?: LngLatTuple;
		zoom?: number;
		baseLayer?: 'osm' | 'satellite';
		showNavigationControl?: boolean;
		showScaleControl?: boolean;
		children?: Snippet;
		onReady?: (map: IMap) => void;
	}

	let {
		center = [129.1234, 62.1234],
		zoom = 4,
		baseLayer = 'osm',
		showNavigationControl = true,
		showScaleControl = true,
		children,
		onReady,
	}: Props = $props();

	let container: HTMLDivElement;
	let map: IMap | null = $state(null);
	/**
	 * Children must not render until the map's first `load` event. MapLibre
	 * throws if addSource/addLayer is called on an unloaded style, and this
	 * component is the natural gate for that invariant.
	 */
	let ready = $state(false);

	setMapContext(() => map);

	export function getInstance(): IMap | null {
		return map;
	}

	onMount(() => {
		map = createMapLibreMap({
			container,
			center,
			zoom,
			baseLayer,
			showNavigationControl,
			showScaleControl,
		});
		map.ready.then(() => {
			ready = true;
			if (map) {
				onReady?.(map);
				if (import.meta.env.DEV) {
					// Debug handle for e2e tests and console inspection. Only exposed
					// in dev builds; trimmed from production bundles.
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
					(window as any)._lsvMap = map.getRawInstance();
				}
			}
		});
	});

	onDestroy(() => {
		map?.dispose();
		map = null;
		ready = false;
	});
</script>

<div class="map-container" bind:this={container}>
	{#if ready && map}
		{@render children?.()}
	{/if}
</div>
