import { create } from 'zustand';
import { ToolType } from '../types/tools';
import { Geometry, Point } from 'ol/geom';
import OLMap from 'ol/Map';
import { Coordinate } from 'ol/coordinate';
import { IRectCoords, SatelliteMapsProvider } from '../interfaces/map';
import { TypeRole } from '../interfaces/gis';
import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature';
import { containsExtent, Extent } from 'ol/extent';
import { DragBox, Draw, Modify, Select, Snap, Translate } from 'ol/interaction';
import TileLayer from 'ol/layer/Tile';
import { v4 as uuidv4 } from 'uuid';
import { googleMapsSatelliteSource } from '../components/map/MapSources';
import VectorLayer from 'ol/layer/Vector';
import { ImageStatic, OSM } from 'ol/source';
import ImageLayer from 'ol/layer/Image';
import { figureStyle, highlightStyleRed, highlightStyleYellow, lineStyle, overlayStyle, regionsLayerStyle, selectStyle } from '../components/map/MapStyles';
import { Fill, Stroke, Style } from 'ol/style';
import { VectorImage } from 'ol/layer';
import { click, noModifierKeys, pointerMove } from 'ol/events/condition';
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
import MapBrowserEvent from 'ol/MapBrowserEvent';
import { get, transform } from 'ol/proj';
import { applyTransformations, calculateTransformations, fixedAspectRatioBox, getGridCellPosition, zoomToFeature } from '../components/map/mapUtils';
import { getSelectedRegion, setCurrentObjectId, setSelectedDistrict, setSelectedRegion } from './objects';
import View from 'ol/View';
import { getPrintOrientation } from './print';
import { getDistrictsData, getRegionsData } from './regions';

export type Mode = 'edit' | 'view' | 'print'

export type PrintScale = '500' | '250' | '50' | '25' | '10'

export type PrintOrientation = 'horizontal' | 'vertical'

interface MapState {
    id: Record<string, {
        currentTool: ToolType;
        measureType: "LineString" | "Polygon";
        measureShowSegments: boolean;
        measureClearPrevious: boolean;
        tipPoint: Point | null;
        map: OLMap | null;
        currentZ: number | undefined;
        currentX: number | undefined;
        currentY: number | undefined;
        currentCoordinate: Coordinate | null;
        statusText: string | null;
        statusTextPosition: [number, number];
        satMapsProvider: SatelliteMapsProvider;
        selectedObjectType: number | null;
        alignMode: boolean;
        mode: Mode;
        typeRoles: TypeRole[] | null;
        mapLabel: string;
        file: File | null;
        measureSource: VectorSource<Feature<Geometry>>;
        measureDraw: Draw | null;
        polygonExtent: Extent | undefined;
        rectCoords: IRectCoords | undefined;
        alignPoints: Coordinate[];
        alignModeLayer: VectorLayer;
        drawingLayer: VectorLayer;
        drawingLayerSource: VectorSource;
        draw: Draw | null;
        snap: Snap | null;
        translate: Translate | null;
        overlayLayerSource: VectorSource;
        satLayer: TileLayer;
        staticMapLayer: ImageLayer<ImageStatic>;
        figuresLayer: VectorLayer<VectorSource>;
        linesLayer: VectorLayer<VectorSource>;
        regionsLayer: VectorImage;
        districtsLayer: VectorImage;
        districtBoundLayer: VectorImage;
        imageLayer: ImageLayer<ImageStatic>;
        selectedArea: Feature | null;
        baseLayer: TileLayer;
        measureLayer: VectorLayer;
        measureModify: Modify;
        overlayLayer: VectorLayer;
        regionSelect: Select;
        districtSelect: Select;
        lineSelect: Select;
        previousView: View | undefined | null;
        printArea: Extent | null;
        printLayer: VectorLayer;
        printSource: VectorSource;
        printAreaDraw: Draw;
        printPreviewSize: number[];
        printDim: 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5';
        printRes: number;
        printOrientation: PrintOrientation;
        printScale: PrintScale;
        printScaleLine: boolean;
        selectionDragBox: DragBox;
        capitalsLayer: VectorLayer
        selectedFeatures: Feature<Geometry>[]
        changes: Map<string, any>
        currentChange: string | undefined
    }>;
}

export const useMapStore = create<MapState>(() => ({
    id: {}
}))

export const initializeMapState = (
    id: string
) => {
    useMapStore.setState((state) => {
        const hitTolerance = 10

        const baseLayer = new TileLayer({ source: new OSM(), properties: { id: uuidv4(), name: 'OpenStreetMap' } })

        const satLayer = new TileLayer({ source: googleMapsSatelliteSource, visible: false, properties: { id: uuidv4(), name: 'Спутник' } })

        const staticMapLayer = new ImageLayer<ImageStatic>({ properties: { id: uuidv4(), name: 'Подложка' } })

        // Region select
        const regionSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'region' })

        const districtSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'district' })

        // Line select
        const lineSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', })
        lineSelect.on('select', (e) => {
            if (e.selected[0]) {
                setCurrentObjectId(id, e.selected[0].get('object_id'))
                zoomToFeature(id, e.selected[0])
            }
        })

        const lineHover = new Select({ condition: pointerMove, style: highlightStyleYellow, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', })

        // Figure select
        const figureSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'figure' })
        figureSelect.on('select', (e) => {
            if (e.selected[0]) {
                setCurrentObjectId(id, e.selected[0].get('object_id'))
                zoomToFeature(id, e.selected[0])
            }
        })
        const figureHover = new Select({ condition: pointerMove, style: highlightStyleYellow, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'figure', })

        const measureSource = new VectorSource()
        const measureLayer = new VectorLayer({
            source: measureSource,
            style: (feature) => measureStyleFunction(id, feature),
            properties: { id: uuidv4(), type: 'measure', name: 'Линейка' }
        })
        const measureModify = new Modify({
            source: measureSource,
            style: modifyStyle
        })

        const overlayLayerSource = new VectorSource()
        const overlayLayer = new VectorLayer({
            source: overlayLayerSource,
            style: overlayStyle,
            properties: {
                id: uuidv4(),
                name: 'Наложения'
            }
        })

        const drawingLayerSource = new VectorSource()
        const drawingLayer = new VectorLayer({
            source: drawingLayerSource
        })

        const regionsLayer = new VectorImage({
            source: new VectorSource(),
            declutter: true,
            style: regionsLayerStyle,
            properties: {
                id: uuidv4(),
                name: 'Регион',
                type: 'region'
            }
        })

        const capitalsLayer = new VectorLayer({
            source: new VectorSource(),
            declutter: true,
            properties: {
                id: uuidv4(),
                name: 'Capitals',
                type: 'capital'
            }
        })

        const districtBoundLayer = new VectorImage({ style: new Style({ stroke: new Stroke({ color: 'red', width: 2 }), }) })

        const districtsLayer = new VectorImage({ source: new VectorSource(), properties: { id: uuidv4(), name: 'Населенные пункты', type: 'district' } })

        const linesLayer = new VectorLayer({
            source: new VectorSource(),
            declutter: true,
            properties: { id: uuidv4(), type: 'line', name: 'Линии' },
            style: function (feature) {
                const objectType = feature.get('type')
                const typeRole = getTypeRoles(id)?.find((el) => el.id.toString() === String(objectType))
                if (typeRole) {
                    lineStyle.setStroke(new Stroke({
                        color: `rgb(${typeRole.r},${typeRole.g},${typeRole.b})`
                    }))
                }
                //lineStyle.getText()?.setText('11,4')//(feature.get('object_id'))
                lineStyle.getText()?.setRotation(feature.get('rotation'))
                lineStyle.getText()?.setOffsetY(-8)
                return lineStyle
            },
        })

        const figuresLayer = new VectorLayer({
            source: new VectorSource(),
            declutter: true,
            properties: { id: uuidv4(), type: 'figure', name: 'Фигуры' },
            style: function (feature) {
                const objectType = feature.get('type')
                const typeRole = getTypeRoles(id)?.find((el) => el.id.toString() === String(objectType))

                if (typeRole) {
                    figureStyle.setFill(new Fill({
                        color: `rgb(${typeRole.r},${typeRole.g},${typeRole.b})`
                    }))
                }

                figureStyle.getText()?.setText(feature.get('object_id'))
                return figureStyle
            }
        })

        const imageLayer = new ImageLayer<ImageStatic>({ properties: { id: uuidv4(), name: 'Изображение' } })

        const alignModeLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), type: 'align', name: 'Подгонка' } })


        const printSource = new VectorSource()
        const printLayer = new VectorLayer({
            source: printSource
        })
        const printAreaDraw = new Draw({
            source: printSource,
            type: 'Circle',
            style: () => {
                return new Style({
                    fill: new Fill({
                        color: "rgba(0, 0, 255, 0.3)", // Semi-transparent blue fill
                    }),
                    stroke: new Stroke({
                        color: "blue",
                        width: 2,
                    }),
                    image: undefined, // 🚀 This removes the default point!
                });
            },
            geometryFunction: function (coords, geom) {
                const printOrientation = getPrintOrientation()
                return fixedAspectRatioBox(coords, geom, printOrientation)
            },
        })

        printAreaDraw.on('drawend', (e) => {
            const extent = e.feature.getGeometry()?.getExtent()
            if (extent) {
                setPrintArea(id, extent)
            }
        })

        const selectionDragBox = new DragBox({
            condition: noModifierKeys
        })

        selectionDragBox.on('boxend', () => {
            const extent = selectionDragBox.getGeometry().getExtent()

            const figuresSource = figuresLayer.getSource()
            const linesSource = linesLayer.getSource()

            if (figuresSource && linesSource) {
                const featuresFigures = figuresSource.getFeaturesInExtent(extent);
                const featuresLines = linesSource.getFeaturesInExtent(extent);

                const intersectingFigures = featuresFigures.filter(feature => {
                    const geometry = feature.getGeometry();
                    if (!geometry) return false;

                    // Create polygon from extent

                    // Check for intersection
                    return geometry.intersectsExtent(extent);
                })

                const intersectingLines = featuresLines.filter(feature => {
                    const geometry = feature.getGeometry();
                    if (!geometry) return false;

                    // Create polygon from extent

                    // Check for intersection
                    return geometry.intersectsExtent(extent);
                });

                setSelectedFeatures(id, [...intersectingFigures, ...intersectingLines])
            }
        })

        const map = new OLMap({
            controls: [],
            layers: [
                baseLayer,
                satLayer,
                staticMapLayer,
                linesLayer,
                districtsLayer,
                districtBoundLayer,
                regionsLayer,
                capitalsLayer,
                figuresLayer,
                drawingLayer,
                imageLayer,
                overlayLayer,
                measureLayer,
                alignModeLayer,
                printLayer
            ]
        })

        map.addInteraction(regionSelect)
        map.addInteraction(districtSelect)
        map.addInteraction(lineSelect)
        map.addInteraction(lineHover)
        map.addInteraction(figureSelect)
        map.addInteraction(figureHover)

        const pointerHandler = (e: MapBrowserEvent<UIEvent>) => {
            setCurrentCoordinate(id, e.coordinate)
            const currentExtent = get('EPSG:3857')?.getExtent() as Extent
            const { tileX, tileY } = getGridCellPosition(e.coordinate[0], e.coordinate[1], currentExtent, Number(map?.getView().getZoom()?.toFixed(0)))
            setCurrentZ(id, Number(map?.getView().getZoom()?.toFixed(0)))
            setCurrentX(id, tileX)
            setCurrentY(id, tileY)

            const pixel = map?.getEventPixel(e.originalEvent)
            if (pixel) {
                let found = false;
                map?.forEachFeatureAtPixel(pixel, (feature, layer) => {
                    if (layer.get("type") === "region" && feature.get("entity_id")) {
                        found = true

                        const name = getRegionsData()?.find(region => region.id === feature.get("entity_id"))?.name || feature.get("entity_id") || ""
                        setStatusText(id, name);
                        setStatusTextPosition(id, pixel[0], pixel[1]);
                    }

                    if (layer.get("type") === "district" && feature.get("entity_id")) {
                        found = true

                        const name = getDistrictsData()?.find(district => district.id === feature.get("entity_id"))?.name || feature.get("entity_id") || ""
                        setStatusText(id, name);
                        setStatusTextPosition(id, pixel[0], pixel[1]);
                    }

                    if (layer.get("type") === "capital" && feature.get("entity_id")) {
                        found = true

                        setStatusText(id, feature.get("entity_id"))
                        setStatusTextPosition(id, pixel[0], pixel[1]);
                    }
                });

                if (!found) {
                    setStatusText(id, null);
                }
            }
        }

        map.on('pointermove', pointerHandler)

        map.on('click', function (e: MapBrowserEvent<UIEvent>) {
            if (getAlignMode(id)) {
                const alignPoints = getAlignPoints(id)
                const alignModeLayer = getAlignModeLayer(id)
                if (alignPoints.length < 4) {
                    //setAlignPoints(id, [...alignPoints, e.coordinate])
                    alignPoints.push(e.coordinate)
                    alignModeLayer.getSource()?.addFeature(new Feature(new Point(e.coordinate)))
                    if (alignPoints.length === 4) {
                        const transformations = calculateTransformations(alignPoints);
                        // Use the first map point (P3) as the origin for scaling and rotation
                        const origin = alignPoints[2];
                        applyTransformations(getFiguresLayer(id), transformations, origin);
                        applyTransformations(getLinesLayer(id), transformations, origin);

                        setAlignPoints(id, [])
                        alignModeLayer.getSource()?.clear()
                    }
                }
            } else {
                const pixel = map?.getEventPixel(e.originalEvent)

                if (pixel) {
                    map?.forEachFeatureAtPixel(pixel, function (feature, layer) {
                        if (layer) {
                            if (layer.get('type') === 'region' && layer.getOpacity() !== 0) {
                                zoomToFeature(id, feature as Feature)

                                if (feature.get('entity_id')) {
                                    setSelectedRegion(id, feature.get('entity_id'))

                                    //regionsLayer.setVisible(false)
                                    //regionsLayer.setOpacity(0)
                                    map.removeInteraction(regionSelect)
                                }
                            }

                            if (layer.get('type') === 'district' && layer.getOpacity() !== 0) {
                                zoomToFeature(id, feature as Feature)

                                if (feature.get('entity_id')) {
                                    setSelectedDistrict(id, feature.get('entity_id'))

                                    map.removeInteraction(districtSelect)
                                }
                            }
                        }
                    })
                }
            }
        })

        map.on('moveend', function () {
            const viewExtent = map?.getView().calculateExtent(map.getSize())
            const features = regionsLayer.getSource()?.getFeatures()

            let isViewCovered = false

            features?.forEach((feature: Feature) => {
                const featureExtent = feature?.getGeometry()?.getExtent()
                if (viewExtent && featureExtent) {
                    if (containsExtent(featureExtent, viewExtent)) {
                        isViewCovered = true
                    }
                }
            })

            if (!getSelectedRegion(id)) {
                regionsLayer.setOpacity(isViewCovered ? 0 : 1)
            }
        })

        map.setView(
            new View({
                center: transform([129.7466541, 62.083504], 'EPSG:4326', 'EPSG:3857'),//center: fromLonLat([130.401113, 67.797368]),
                zoom: 5,
                maxZoom: 21,
                //extent: mapExtent,
            })
        )

        return {
            id: {
                ...state.id,
                [id]: {
                    currentTool: null,
                    measureType: "LineString",
                    measureShowSegments: true,
                    measureClearPrevious: true,
                    tipPoint: null,
                    map: map,
                    currentZ: undefined,
                    currentX: undefined,
                    currentY: undefined,
                    currentCoordinate: null,
                    statusText: null,
                    statusTextPosition: [0, 0],
                    satMapsProvider: 'google',
                    selectedObjectType: null,
                    alignMode: false,
                    mode: 'view',
                    typeRoles: null,
                    mapLabel: 'Карта',
                    file: null,
                    measureSource: measureSource,
                    measureDraw: null,
                    polygonExtent: undefined,
                    rectCoords: undefined,
                    alignPoints: [],
                    alignModeLayer: alignModeLayer,
                    drawingLayer: drawingLayer,
                    drawingLayerSource: drawingLayerSource,
                    draw: null,
                    snap: null,
                    translate: null,
                    overlayLayerSource: overlayLayerSource,
                    satLayer: satLayer,
                    staticMapLayer: staticMapLayer,
                    figuresLayer: figuresLayer,
                    linesLayer: linesLayer,
                    districtsLayer: districtsLayer,
                    regionsLayer: regionsLayer,
                    districtBoundLayer: districtBoundLayer,
                    imageLayer: imageLayer,
                    selectedArea: null,
                    baseLayer: baseLayer,
                    measureLayer: measureLayer,
                    measureModify: measureModify,
                    overlayLayer: overlayLayer,
                    districtSelect: districtSelect,
                    regionSelect: regionSelect,
                    lineSelect: lineSelect,
                    previousView: null,
                    printArea: null,
                    printLayer: printLayer,
                    printSource: printSource,
                    printAreaDraw: printAreaDraw,
                    printPreviewSize: [640, 320],
                    printDim: 'a4',
                    printOrientation: 'horizontal',
                    printRes: 72,
                    printScale: '250',
                    printScaleLine: true,
                    selectionDragBox: selectionDragBox,
                    capitalsLayer: capitalsLayer,
                    selectedFeatures: [],
                    changes: new Map(),
                    currentChange: undefined
                }
            }
        }
    })
}

export const getCurrentChange = (id: string) => useMapStore.getState().id[id].currentChange
export const setCurrentChange = (id: string, currentChange: string | undefined) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], currentChange: currentChange }
        }
    }
})

export const cleanChanges = (id: string) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], changes: new Map(), currentChange: undefined }
        }
    }
})

export const getChanges = (id: string) => useMapStore.getState().id[id].changes
export const addChanges = (id: string, changes: any) => useMapStore.setState((state) => {
    const uid = uuidv4()
    const date = new Date().getTime()
    const key = `${date}-${uid}`

    const mapState = state.id[id]
    const currentChanges = new Map(mapState.changes)
    const currentChangeKey = mapState.currentChange

    // If we're not at the latest change (we've undone), 
    // delete all changes after currentChange
    if (currentChangeKey) {
        let shouldDelete = false
        const entries = Array.from(currentChanges.entries())

        // Find entries after currentChangeKey
        for (let i = 0; i < entries.length; i++) {
            const [entryKey] = entries[i]

            if (entryKey === currentChangeKey) {
                // From next entry onward, mark for deletion
                shouldDelete = true
            } else if (shouldDelete) {
                currentChanges.delete(entryKey)
            }
        }
    }

    // Add the new change
    currentChanges.set(key, changes)

    return {
        id: {
            ...state.id,
            [id]: {
                ...mapState,
                changes: currentChanges,
                currentChange: key
            }
        }
    }
})

export const getSelectionDragBox = (id: string) => useMapStore.getState().id[id].selectionDragBox

export const setPrintOrientation = (id: string, orientation: PrintOrientation) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], printOrientation: orientation }
        }
    }
})

export const setPrintScaleLine = (id: string, bool: boolean) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], printScaleLine: bool }
        }
    }
})

export const setPrintScale = (id: string, printScale: PrintScale) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], printScale: printScale }
        }
    }
})

export const setPreviousView = (id: string, view: View | undefined | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], previousView: view }
        }
    }
})

export const clearPrintArea = (id: string) => useMapStore.setState((state) => {
    state.id[id].printSource.clear()

    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], printArea: null }
        }
    }
})

export const setPrintArea = (id: string, extent: Extent | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], printArea: extent }
        }
    }
})

export const getFiguresLayer = (id: string) => useMapStore.getState().id[id].figuresLayer
export const getLinesLayer = (id: string) => useMapStore.getState().id[id].linesLayer
export const getMeasureModify = (id: string) => useMapStore.getState().id[id].measureModify

export const getOverlayLayerSource = (id: string) => useMapStore.getState().id[id].overlayLayerSource
export const setOverlayLayerSource = (id: string, source: VectorSource) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], overlayLayerSource: source }
        }
    }
})

export const getImageLayer = (id: string) => useMapStore.getState().id[id].imageLayer
export const setImageLayer = (id: string, layer: ImageLayer<ImageStatic>) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], imageLayer: layer }
        }
    }
})

export const getTranslate = (id: string) => useMapStore.getState().id[id].translate
export const setTranslate = (id: string, translate: Translate | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], translate: translate }
        }
    }
})

export const getSnap = (id: string) => useMapStore.getState().id[id].snap
export const setSnap = (id: string, snap: Snap | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], snap: snap }
        }
    }
})

export const getDraw = (id: string) => useMapStore.getState().id[id].draw
export const setDraw = (id: string, draw: Draw | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], draw: draw }
        }
    }
})

export const getDrawingLayerSource = (id: string) => useMapStore.getState().id[id].drawingLayerSource
export const getMeasureSource = (id: string) => useMapStore.getState().id[id].measureSource
export const getMeasureDraw = (id: string) => useMapStore.getState().id[id].measureDraw

export const setMeasureDraw = (id: string, draw: Draw) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], measureDraw: draw }
        }
    }
})

export const setAlignPoints = (id: string, c: Coordinate[]) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], alignPoints: c }
        }
    }
})

export const setRectCoords = (id: string, c: IRectCoords | undefined) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], rectCoords: c }
        }
    }
})

export const setPolygonExtent = (id: string, extent: Extent | undefined) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], polygonExtent: extent }
        }
    }
})

export const setFile = (id: string, file: File | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], file: file }
        }
    }
})

export const setMapLabel = (id: string, label: string) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], mapLabel: label }
        }
    }
})

export const setCurrentZ = (id: string, z: number | undefined) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], currentZ: z }
        }
    }
})

export const setCurrentX = (id: string, x: number | undefined) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], currentX: x }
        }
    }
})

export const setCurrentY = (id: string, y: number | undefined) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], currentY: y }
        }
    }
})

export const setCurrentCoordinate = (id: string, c: Coordinate | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], currentCoordinate: c }
        }
    }
})

export const setStatusTextPosition = (id: string, left: number, top: number) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], statusTextPosition: [left, top] }
        }
    }
})

export const setStatusText = (id: string, t: string | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], statusText: t }
        }
    }
})

export const setSatMapsProvider = (id: string, p: SatelliteMapsProvider) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], satMapsProvider: p }
        }
    }
})

export const setSelectedObjectType = (id: string, t: number | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], selectedObjectType: t }
        }
    }
})

export const setMap = (id: string, m: OLMap | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], map: m }
        }
    }
})

export const setAlignMode = (id: string, m: boolean) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], alignMode: m }
        }
    }
})

export const setTipPoint = (id: string, tipPoint: Point | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], tipPoint: tipPoint }
        }
    }
})

export const getTipPoint = (id: string) => useMapStore.getState().id[id].tipPoint

export const getAlignMode = (id: string) => useMapStore.getState().id[id].alignMode

export const getAlignModeLayer = (id: string) => useMapStore.getState().id[id].alignModeLayer

export const getAlignPoints = (id: string) => useMapStore.getState().id[id].alignPoints

export const getMap = (id: string) => useMapStore.getState().id[id].map

export const setMeasureType = (id: string, tool: "LineString" | "Polygon") => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], measureType: tool }
        }
    }
})

export const getMeasureType = (id: string) => useMapStore.getState().id[id].measureType

export const setCurrentTool = (id: string, tool: ToolType) =>
    tool === useMapStore.getState().id[id].currentTool
        ? useMapStore.setState((state) => {
            return {
                id: {
                    ...state.id,
                    [id]: { ...state.id[id], currentTool: null }
                }
            }
        })
        : useMapStore.setState((state) => {
            return {
                id: {
                    ...state.id,
                    [id]: { ...state.id[id], currentTool: tool }
                }
            }
        })

export const getCurrentTool = (id: string) => useMapStore.getState().id[id].currentTool

export const getMeasureShowSegments = (id: string) => useMapStore.getState().id[id].measureShowSegments

export const getMeasureClearPrevious = (id: string) => useMapStore.getState().id[id].measureClearPrevious

export const setMeasureShowSegments = (id: string, bool: boolean) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], measureShowSegments: bool }
        }
    }
})

export const setMeasureClearPrevious = (id: string, bool: boolean) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], measureClearPrevious: bool }
        }
    }
})

export const getMode = (id: string) => useMapStore.getState().id[id].mode
export const setMode = (id: string, mode: Mode) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], mode: mode }
        }
    }
})

export const getTypeRoles = (id: string) => useMapStore.getState().id[id].typeRoles
export const setTypeRoles = (id: string, typeRoles: TypeRole[] | null) => useMapStore.setState((state) => {
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], typeRoles: typeRoles }
        }
    }
})

export const getSelectedFeatures = (id: string) => useMapStore.getState().id[id].selectedFeatures

export const setSelectedFeatures = (id: string, selectedFeatures: Feature<Geometry>[]) => useMapStore.setState((state) => {
    // set default style for previously selected features
    state.id[id].selectedFeatures.map(f => f.setStyle(undefined))
    selectedFeatures.map(f => f.setStyle(highlightStyleYellow))
    return {
        id: {
            ...state.id,
            [id]: { ...state.id[id], selectedFeatures: selectedFeatures }
        }
    }
})