<script lang="ts">
    import type {SpecialVisualizationState} from "../SpecialVisualization";
    import LocationInput from "../InputElement/Helpers/LocationInput.svelte";
    import {UIEventSource} from "../../Logic/UIEventSource";
    import {Tiles} from "../../Models/TileRange";
    import {Map as MlMap} from "maplibre-gl";
    import {BBox} from "../../Logic/BBox";
    import type {MapProperties} from "../../Models/MapProperties";
    import ShowDataLayer from "../Map/ShowDataLayer";
    import type {FeatureSource, FeatureSourceForLayer} from "../../Logic/FeatureSource/FeatureSource";
    import SnappingFeatureSource from "../../Logic/FeatureSource/Sources/SnappingFeatureSource";
    import FeatureSourceMerger from "../../Logic/FeatureSource/Sources/FeatureSourceMerger";
    import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
    import {Utils} from "../../Utils";

    /**
     * An advanced location input, which has support to:
     * - Show more layers
     * - Snap to layers
     *
     * This one is mostly used to insert new points
     */
    export let state: SpecialVisualizationState;
    /**
     * The start coordinate
     */
    export let coordinate: { lon: number, lat: number };
    export let snapToLayers: string[] | undefined;
    export let targetLayer: LayerConfig;
    export let maxSnapDistance: number = undefined;

    export let snappedTo: UIEventSource<string | undefined>;
    
    export let value: UIEventSource<{ lon: number, lat: number }>;
    if (value.data === undefined) {
        value.setData(coordinate);
    }

    let preciseLocation: UIEventSource<{ lon: number, lat: number }> = new UIEventSource<{
        lon: number;
        lat: number
    }>(undefined);
    
    const xyz = Tiles.embedded_tile(coordinate.lat, coordinate.lon, 16);
    const map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined);
    let initialMapProperties: Partial<MapProperties> = {
        zoom: new UIEventSource<number>(19),
        maxbounds: new UIEventSource(undefined),
        /*If no snapping needed: the value is simply the map location;
        * If snapping is needed: the value will be set later on by the snapping feature source
        * */
        location: snapToLayers?.length > 0 ? new UIEventSource<{ lon: number; lat: number }>(coordinate) : value,
        bounds: new UIEventSource<BBox>(undefined),
        allowMoving: new UIEventSource<boolean>(true),
        allowZooming: new UIEventSource<boolean>(true),
        minzoom: new UIEventSource<number>(18),
        rasterLayer: UIEventSource.feedFrom(state.mapProperties.rasterLayer)
    };
  
    
    const featuresForLayer = state.perLayer.get(targetLayer.id)
    if(featuresForLayer){
        new ShowDataLayer(map, {
            layer: targetLayer,
            features: featuresForLayer
        })
    }
    

    if (snapToLayers?.length > 0) {

        const snapSources: FeatureSource[] = [];
        for (const layerId of (snapToLayers ?? [])) {
            const layer: FeatureSourceForLayer = state.perLayer.get(layerId);
            snapSources.push(layer);
            if (layer.features === undefined) {
                continue;
            }
            new ShowDataLayer(map, {
                layer: layer.layer.layerDef,
                zoomToFeatures: false,
                features: layer
            });
        }
        const snappedLocation = new SnappingFeatureSource(
            new FeatureSourceMerger(...Utils.NoNull(snapSources)),
            // We snap to the (constantly updating) map location
            initialMapProperties.location,
            {
                maxDistance: maxSnapDistance ?? 15,
                allowUnsnapped: true,
                snappedTo,
                snapLocation: value
            }
        );

        new ShowDataLayer(map, {
            layer: targetLayer,
            features: snappedLocation
        });
    }


</script>


<LocationInput {map} mapProperties={initialMapProperties}
               value={preciseLocation} initialCoordinate={{...coordinate}} maxDistanceInMeters=50 />