import { useCallback, useEffect, useRef, useState } from 'react'
import 'ol/ol.css'
import Map from 'ol/Map'
import View from 'ol/View'
import { Draw, Modify, Select, Snap, Translate } from 'ol/interaction'
import { ImageStatic, OSM, Vector as VectorSource } from 'ol/source'
import { Tile as TileLayer, VectorImage, Vector as VectorLayer } from 'ol/layer'
import { click, never, platformModifierKeyOnly, primaryAction, shiftKeyOnly } from 'ol/events/condition'
import Feature from 'ol/Feature'
import { IRectCoords, SatelliteMapsProvider } from '../../interfaces/map'
import { Extent, getCenter } from 'ol/extent'
import { drawingLayerStyle, figureStyle, highlightStyleRed, highlightStyleYellow, lineStyle, overlayStyle, regionsLayerStyle } from './MapStyles'
import { customMapSource, googleMapsSatelliteSource, regionsLayerSource, yandexMapsSatelliteSource } from './MapSources'
import ImageLayer from 'ol/layer/Image'
import { Geometry, LineString, Point, SimpleGeometry } from 'ol/geom'
import { fromExtent } from 'ol/geom/Polygon'
import Collection from 'ol/Collection'
import { Coordinate } from 'ol/coordinate'
import { addInteractions, calculateCenter, loadFeatures, processFigure, processLine, regionsInit, saveFeatures, updateImageSource } from './mapUtils'
import MapBrowserEvent from 'ol/MapBrowserEvent'
import { get, transform } from 'ol/proj'
import useSWR, { SWRConfiguration } from 'swr'
import { fetcher } from '../../http/axiosInstance'
import { BASE_URL } from '../../constants'
import { ActionIcon, Autocomplete, Box, CloseButton, Flex, Select as MantineSelect, MantineStyleProp, rem, useMantineColorScheme, Portal, Menu, Button, Group, Divider, LoadingOverlay } from '@mantine/core'
import { IconBoxMultiple, IconBoxPadding, IconChevronDown, IconPlus, IconSearch, IconUpload } from '@tabler/icons-react'
import { getGridCellPosition } from './mapUtils'
import { IFigure, ILine } from '../../interfaces/gis'
import axios from 'axios'
import MapToolbar from './MapToolbar/MapToolbar'
import MapStatusbar from './MapStatusbar/MapStatusbar'
import { measureStyleFunction, modifyStyle } from './Measure/MeasureStyles'
import { setCurrentCoordinate, setCurrentX, setCurrentY, setCurrentZ, setAlignMode, setSatMapsProvider, useMapStore, getAlignMode } from '../../store/map'
import { v4 as uuidv4 } from 'uuid'
import { useThrottle } from '@uidotdev/usehooks'
import ObjectTree from '../Tree/ObjectTree'
import { setCurrentObjectId, setSelectedDistrict, setSelectedRegion, setSelectedYear, useObjectsStore } from '../../store/objects'
import MapLayers from './MapLayers/MapLayers'
import ObjectParameters from './ObjectParameters/ObjectParameters'
import TabsPane, { ITabsPane } from './TabsPane/TabsPane'
import { useSearchParams } from 'react-router-dom'
import GeoJSON from 'ol/format/GeoJSON'
import { Stroke, Style } from 'ol/style'

const swrOptions: SWRConfiguration = {
    revalidateOnFocus: false
}

// Tab settings
const objectsPane: ITabsPane[] = [
    {
        title: 'Объекты',
        value: 'objects',
        view: <ObjectTree />
    },
    {
        title: 'Неразмещенные',
        value: 'unplaced',
        view: <></>
    },
    {
        title: 'Другие',
        value: 'other',
        view: <></>
    },
]

const paramsPane: ITabsPane[] = [
    {
        title: 'История изменений',
        value: 'history',
        view: <></>
    },
    {
        title: 'Параметры',
        value: 'parameters',
        view: <ObjectParameters />
    },
    {
        title: 'Вычисляемые',
        value: 'calculated',
        view: <></>
    },
]

interface ICitySettings {
    city_id: number;
    image_width: number;
    image_height: number;
    scale: number;
    offset_x: number;
    offset_y: number;
    rotation: number;
    image_scale: number;
}

// Settings for cities
const citySettings: ICitySettings[] = [
    {
        city_id: 145,
        image_width: 8500,
        image_height: 12544,
        scale: 9000,
        offset_x: 14442665.697619518,
        offset_y: 8884520.63524492,
        rotation: 0,
        image_scale: 0.40340
    },
    {
        city_id: 146,
        image_width: 8500,
        image_height: 12544,
        scale: 8000,
        offset_x: 14416475.697619518,
        offset_y: 8889280.63524492,
        rotation: 0,
        image_scale: 0.30340
    }
]

function getCitySettings(
    city_id: number
) {
    const settings = citySettings.find(el => el.city_id === city_id)

    if (settings) {
        //console.log("City settings found")
        return settings
    } else {
        //console.log("City settings NOT found")
        return {
            city_id: 0,
            image_width: 8500,
            image_height: 12544,
            scale: 9000,
            offset_x: 14442665.697619518,
            offset_y: 8884520.63524492,
            rotation: 0
        } as ICitySettings
    }
}

const MapComponent = () => {
    const { colorScheme } = useMantineColorScheme()

    // States
    const { selectedYear, currentObjectId, selectedRegion, selectedDistrict } = useObjectsStore()
    const { currentTool, satMapsProvider, selectedObjectType, alignMode } = useMapStore()
    ///

    const [file, setFile] = useState<File | null>(null)
    const [polygonExtent, setPolygonExtent] = useState<Extent | undefined>(undefined)

    const [rectCoords, setRectCoords] = useState<IRectCoords | undefined>(undefined)

    // Measure
    const measureSource = useRef(new VectorSource())
    const measureModify = useRef(new Modify({ source: measureSource.current, style: modifyStyle }))

    const measureLayer = useRef(new VectorLayer({
        source: measureSource.current,
        style: function (feature) {
            return measureStyleFunction(feature);
        },
        properties: {
            id: uuidv4(),
            type: 'measure',
            name: 'Линейка'
        }
    }))

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

    function calculateTransformations(alignPoints: Coordinate[]) {
        const [P1, P2, P3, P4] = alignPoints;

        // Translation vector (move P1 to P3)
        const translation = [P3[0] - P1[0], P3[1] - P1[1]];

        // Scaling factor (distance between P3 and P4 divided by P1 and P2)
        const distanceLayer = Math.sqrt((P2[0] - P1[0]) ** 2 + (P2[1] - P1[1]) ** 2);
        const distanceMap = Math.sqrt((P4[0] - P3[0]) ** 2 + (P4[1] - P3[1]) ** 2);
        const scale = distanceMap / distanceLayer;

        // Rotation angle (difference in angles between the two lines)
        const angleLayer = Math.atan2(P2[1] - P1[1], P2[0] - P1[0]);
        const angleMap = Math.atan2(P4[1] - P3[1], P4[0] - P3[0]);
        const rotation = angleMap - angleLayer;

        return { translation, scale, rotation };
    }

    function applyTransformations(figuresLayer: React.MutableRefObject<VectorLayer>, transformations: {
        translation: number[];
        scale: number;
        rotation: number;
    }, origin: Coordinate) {
        const { translation, scale, rotation } = transformations;

        const source = figuresLayer.current.getSource();
        if (!source) return;

        source.getFeatures().forEach((feature) => {
            const geometry = feature.getGeometry();

            if (geometry) {
                // Translate
                geometry.translate(translation[0], translation[1]);

                // Scale (around the origin)
                geometry.scale(scale, scale, origin);

                // Rotate (around the origin)
                geometry.rotate(rotation, origin);
            }
        });

        console.log("Transformations applied to figuresLayer");
    }


    const alignPoints = useRef<Coordinate[]>([])

    const measureDraw = useRef<Draw | null>(null)

    const mapElement = useRef<HTMLDivElement | null>(null)

    const tooltipRef = useRef<HTMLDivElement | null>(null)

    const map = useRef<Map | null>(null)

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

    const draw = useRef<Draw | null>(null)
    const snap = useRef<Snap | null>(null)
    const translate = useRef<Translate | null>(null)

    const selectFeature = useRef<Select>(new Select({
        condition: function (mapBrowserEvent) {
            return click(mapBrowserEvent) && shiftKeyOnly(mapBrowserEvent)
        },
    }))

    const nodeLayer = useRef<VectorLayer | null>(null)
    const nodeLayerSource = useRef<VectorSource>(new VectorSource())

    const overlayLayer = useRef<VectorLayer | null>(null)
    const overlayLayerSource = useRef<VectorSource>(new VectorSource())

    const drawingLayer = useRef<VectorLayer | null>(null)
    const drawingLayerSource = useRef<VectorSource>(new VectorSource())

    const citiesLayer = useRef<VectorLayer>(new VectorLayer({
        source: new VectorSource(),
        properties: {
            id: uuidv4(),
            name: 'Города'
        }
    }))

    const figuresLayer = useRef<VectorLayer>(new VectorLayer({
        source: new VectorSource(),
        declutter: true,
        properties: {
            id: uuidv4(),
            type: 'figures',
            name: 'Фигуры'
        },
        style: function (feature) {
            figureStyle.getText()?.setText(feature.get('object_id'))
            return figureStyle
        }
    }))

    const linesLayer = useRef<VectorLayer>(new VectorLayer({
        source: new VectorSource(),
        declutter: true,
        properties: {
            id: uuidv4(),
            type: 'lines',
            name: 'Линии'
        },
        style: function (feature) {
            //lineStyle.getText()?.setText('11,4')//(feature.get('object_id'))
            lineStyle.getText()?.setRotation(feature.get('rotation'))
            lineStyle.getText()?.setOffsetY(-8)
            return lineStyle
        }
    }))

    const regionsLayer = useRef<VectorImage>(new VectorImage({
        source: regionsLayerSource,
        declutter: true,
        style: regionsLayerStyle,
        properties: {
            id: uuidv4(),
            name: 'Регион'
        }
    }))

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

    useEffect(() => {
        if (selectedDistrict && selectedYear) {
            const bounds = new VectorSource({
                url: `bounds/cities/${selectedDistrict}.geojson`,
                format: new GeoJSON(),
            })

            districtBoundLayer.current.setSource(bounds)

            bounds.on('featuresloadend', function () {
                // map.current?.setView(new View({
                //     extent: bounds.getExtent()
                // }))
                console.log(bounds.getFeatures().length)
            })
        }
    }, [selectedDistrict, selectedYear])

    const selectedArea = useRef<Feature | null>(null)

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

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

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

    // tile processing
    const handleImageDrop = useCallback((event: DragEvent) => {
        event.preventDefault();
        event.stopPropagation();

        if (!event.dataTransfer?.files) return

        const files = event.dataTransfer.files;
        if (files.length > 0) {
            const file = files[0];
            setFile(file)

            if (file.type.startsWith('image/')) {
                const reader = new FileReader();

                reader.onload = () => {
                    const imageUrl = reader.result as string;
                    const img = new Image();
                    img.src = imageUrl;
                    img.onload = () => {
                        if (map.current) {
                            const view = map.current.getView();
                            const center = view.getCenter() || [0, 0];

                            const width = img.naturalWidth;
                            const height = img.naturalHeight;
                            const resolution = view.getResolution() || 0;

                            const extent = [
                                center[0] - (width * resolution) / 20,
                                center[1] - (height * resolution) / 20,
                                center[0] + (width * resolution) / 20,
                                center[1] + (height * resolution) / 20,
                            ];

                            // Create a polygon feature with the same extent as the image
                            const polygonFeature = new Feature({
                                geometry: fromExtent(extent),
                            });

                            // Add the polygon feature to the drawing layer source
                            overlayLayerSource.current?.addFeature(polygonFeature);

                            // Set up the initial image layer with the extent
                            const imageSource = new ImageStatic({
                                url: imageUrl,
                                imageExtent: extent,
                            });
                            imageLayer.current.setSource(imageSource);

                            //map.current.addLayer(imageLayer.current);

                            // Add interactions for translation and scaling
                            const translate = new Translate({
                                layers: [imageLayer.current],
                                features: new Collection([polygonFeature]),
                            });

                            const defaultStyle = new Modify({ source: overlayLayerSource.current })
                                .getOverlay()
                                .getStyleFunction();

                            const modify = new Modify({
                                insertVertexCondition: never,
                                source: overlayLayerSource.current,
                                condition: function (event) {
                                    return primaryAction(event) && !platformModifierKeyOnly(event);
                                },
                                deleteCondition: never,
                                features: new Collection([polygonFeature]),
                                style: function (feature) {
                                    feature.get('features').forEach(function (modifyFeature: Feature) {
                                        const modifyGeometry = modifyFeature.get('modifyGeometry')
                                        if (modifyGeometry) {
                                            const point = (feature.getGeometry() as Point).getCoordinates()
                                            let modifyPoint = modifyGeometry.point
                                            if (!modifyPoint) {
                                                // save the initial geometry and vertex position
                                                modifyPoint = point;
                                                modifyGeometry.point = modifyPoint;
                                                modifyGeometry.geometry0 = modifyGeometry.geometry;
                                                // get anchor and minimum radius of vertices to be used
                                                const result = calculateCenter(modifyGeometry.geometry0);
                                                modifyGeometry.center = result.center;
                                                modifyGeometry.minRadius = result.minRadius;
                                            }
                                            const center = modifyGeometry.center;
                                            const minRadius = modifyGeometry.minRadius;
                                            let dx, dy;
                                            dx = modifyPoint[0] - center[0];
                                            dy = modifyPoint[1] - center[1];
                                            const initialRadius = Math.sqrt(dx * dx + dy * dy);
                                            if (initialRadius > minRadius) {
                                                const initialAngle = Math.atan2(dy, dx);
                                                dx = point[0] - center[0];
                                                dy = point[1] - center[1];
                                                const currentRadius = Math.sqrt(dx * dx + dy * dy);
                                                if (currentRadius > 0) {
                                                    const currentAngle = Math.atan2(dy, dx);
                                                    const geometry = modifyGeometry.geometry0.clone();
                                                    geometry.scale(currentRadius / initialRadius, undefined, center);
                                                    geometry.rotate(currentAngle - initialAngle, center);
                                                    modifyGeometry.geometry = geometry;
                                                }
                                            }
                                        }
                                    })
                                    const res = map?.current?.getView()?.getResolution()
                                    if (typeof res === 'number' && feature && defaultStyle) {
                                        return defaultStyle(feature, res)
                                    }
                                }
                            });

                            translate.on('translateend', () => updateImageSource(imageUrl, imageLayer, polygonFeature, setPolygonExtent, setRectCoords));
                            //modify.on('modifyend', updateImageSource);

                            modify.on('modifystart', function (event) {
                                event.features.forEach(function (feature) {
                                    feature.set(
                                        'modifyGeometry',
                                        { geometry: feature.getGeometry()?.clone() },
                                        true,
                                    );
                                });
                            });

                            modify.on('modifyend', function (event) {
                                event.features.forEach(function (feature) {
                                    const modifyGeometry = feature.get('modifyGeometry');
                                    if (modifyGeometry) {
                                        feature.setGeometry(modifyGeometry.geometry);
                                        feature.unset('modifyGeometry', true);
                                    }
                                })
                                updateImageSource(imageUrl, imageLayer, polygonFeature, setPolygonExtent, setRectCoords)
                            })

                            map.current.addInteraction(translate);
                            map.current.addInteraction(modify);
                        }
                    };
                };
                reader.readAsDataURL(file);
            }
        }
    }, [])

    useEffect(() => {
        drawingLayer.current = new VectorLayer({
            source: drawingLayerSource.current,
            style: drawingLayerStyle,
            properties: {
                id: uuidv4(),
                name: 'Чертеж'
            }
        })

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

        nodeLayer.current = new VectorLayer({
            source: nodeLayerSource.current,
            style: drawingLayerStyle,
            properties: {
                id: uuidv4(),
                name: 'Узлы'
            }
        })

        map.current = new Map({
            controls: [],
            layers: [
                baseLayer.current,
                satLayer.current,
                staticMapLayer.current,
                regionsLayer.current,
                districtBoundLayer.current,
                citiesLayer.current,
                linesLayer.current,
                figuresLayer.current,
                drawingLayer.current,
                imageLayer.current,
                overlayLayer.current,
                nodeLayer.current,
                measureLayer.current,
                alignModeLayer.current
            ],
            target: mapElement.current as HTMLDivElement,
            view: new View({
                center: transform([129.7466541, 62.083504], 'EPSG:4326', 'EPSG:3857'),//center: fromLonLat([130.401113, 67.797368]),
                //zoom: 16,
                zoom: 5,
                maxZoom: 21,
                //extent: mapExtent,
            }),
        })

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

            const pixel = map.current?.getEventPixel(e.originalEvent)
            if (pixel) {
                map.current?.forEachFeatureAtPixel(pixel, function (feature) {
                    if (feature.get('geometry_type') === 'line') {
                        //console.log(feature.getProperties())
                    }
                })
            }
        })

        map.current.on('click', function (e: MapBrowserEvent<UIEvent>) {
            if (getAlignMode()) {
                if (alignPoints.current.length < 4) {
                    alignPoints.current.push(e.coordinate)
                    alignModeLayer.current.getSource()?.addFeature(new Feature(new Point(e.coordinate)))
                    if (alignPoints.current.length === 4) {
                        console.log("collected 4 points, now can align")
                        console.log(alignPoints.current)
                        const transformations = calculateTransformations(alignPoints.current);
                        console.log(transformations)

                        // Use the first map point (P3) as the origin for scaling and rotation
                        const origin = alignPoints.current[2];
                        console.log(origin)

                        applyTransformations(figuresLayer, transformations, origin);
                        applyTransformations(linesLayer, transformations, origin);
                        console.log("Figures layer aligned!")

                        alignPoints.current = []
                        alignModeLayer.current.getSource()?.clear()
                    }
                }
            } else {
                const pixel = map.current?.getEventPixel(e.originalEvent)

                if (pixel) {
                    map.current?.forEachFeatureAtPixel(pixel, function (feature) {
                        setCurrentObjectId(feature.get('object_id'))
                    })
                }
            }
        })

        const modify = new Modify({ source: drawingLayerSource.current })
        map.current.addInteraction(modify)

        map.current.addInteraction(selectFeature.current)

        selectFeature.current.on('select', (e) => {
            const selectedFeatures = e.selected

            if (selectedFeatures.length > 0) {
                selectedFeatures.forEach((feature) => {
                    drawingLayerSource.current?.removeFeature(feature)
                })
            }
        })

        loadFeatures(drawingLayerSource)

        regionsInit(map, selectedArea, regionsLayer)

        if (mapElement.current) {
            mapElement.current.addEventListener('dragover', (e) => {
                e.preventDefault()
            })

            mapElement.current.addEventListener('drop', handleImageDrop)
        }

        return () => {
            map?.current?.setTarget(undefined)

            if (mapElement.current) {
                mapElement.current.removeEventListener('drop', handleImageDrop)
            }
        }
    }, [])

    useEffect(() => {
        if (currentTool) {
            if (draw.current) map?.current?.removeInteraction(draw.current)
            //if (snap.current) map?.current?.removeInteraction(snap.current)
            addInteractions(drawingLayerSource, translate, draw, map, snap, measureDraw, measureSource, measureModify)
        } else {
            if (translate.current) map?.current?.removeInteraction(translate.current)
            if (draw.current) map?.current?.removeInteraction(draw.current)
            if (snap.current) map?.current?.removeInteraction(snap.current)
            if (measureDraw.current) map?.current?.removeInteraction(measureDraw.current)
        }
    }, [currentTool])

    // Satellite tiles setting
    useEffect(() => {
        if (satLayer.current) {
            if (satMapsProvider === 'google') {
                satLayer.current.setSource(googleMapsSatelliteSource)
            }

            if (satMapsProvider === 'yandex') {
                satLayer.current.setSource(yandexMapsSatelliteSource)
            }

            if (satMapsProvider === 'custom') {
                satLayer.current.setSource(customMapSource)
            }
        }
    }, [satMapsProvider, satLayer])

    const submitOverlay = async () => {
        if (file && polygonExtent && rectCoords?.bl && rectCoords?.tl && rectCoords?.tr && rectCoords?.br) {
            const formData = new FormData()
            formData.append('file', file)
            formData.append('extentMinX', polygonExtent[0].toString())
            formData.append('extentMinY', polygonExtent[1].toString())
            formData.append('extentMaxX', polygonExtent[2].toString())
            formData.append('extentMaxY', polygonExtent[3].toString())
            formData.append('blX', rectCoords?.bl[0].toString())
            formData.append('blY', rectCoords?.bl[1].toString())
            formData.append('tlX', rectCoords?.tl[0].toString())
            formData.append('tlY', rectCoords?.tl[1].toString())
            formData.append('trX', rectCoords?.tr[0].toString())
            formData.append('trY', rectCoords?.tr[1].toString())
            formData.append('brX', rectCoords?.br[0].toString())
            formData.append('brY', rectCoords?.br[1].toString())

            await fetch(`${import.meta.env.VITE_API_EMS_URL}/tiles/upload`, { method: 'POST', body: formData })
        }
    }

    const mapControlsStyle: MantineStyleProp = {
        borderRadius: '4px',
        position: 'absolute',
        zIndex: '1',
        backgroundColor: colorScheme === 'light' ? '#F0F0F0CC' : '#000000CC',
        backdropFilter: 'blur(8px)',
        border: '1px solid #00000022'
    }

    const { data: nodes } = useSWR('/nodes/all', () => fetcher('/nodes/all', BASE_URL.ems), { revalidateOnFocus: false })

    useEffect(() => {
        // Draw features based on database data
        if (Array.isArray(nodes)) {
            nodes.map(node => {
                if (node.shape_type === 'LINE') {
                    const coordinates: Coordinate[] = []
                    if (Array.isArray(node.shape)) {
                        node.shape.map((point: { x: number, y: number }) => {
                            const coordinate = [point.x as number, point.y as number] as Coordinate
                            coordinates.push(coordinate)
                        })
                    }
                    //console.log(coordinates)
                    nodeLayerSource.current.addFeature(new Feature({ geometry: new LineString(coordinates) }))
                }
            })
        }
    }, [nodes])

    const [searchObject, setSearchObject] = useState<string | undefined>("")
    const throttledSearchObject = useThrottle(searchObject, 500);

    useEffect(() => {
        if (!selectedObjectType || !map.current) return;

        if (figuresLayer.current) {
            // Reset styles and apply highlight to matching features
            figuresLayer.current.getSource()?.getFeatures().forEach((feature) => {
                if (selectedObjectType == feature.get('type')) {
                    feature.setStyle(highlightStyleYellow);
                } else {
                    feature.setStyle(undefined); // Reset to default style
                }
            })
        }

        if (linesLayer.current) {
            // Reset styles and apply highlight to matching features
            linesLayer.current.getSource()?.getFeatures().forEach((feature) => {
                if (selectedObjectType == feature.get('type')) {
                    feature.setStyle(highlightStyleYellow);
                } else {
                    feature.setStyle(undefined); // Reset to default style
                }
            })
        }
    }, [selectedObjectType])

    useEffect(() => {
        if (currentObjectId) {
            if (figuresLayer.current) {
                // Reset styles and apply highlight to matching features
                figuresLayer.current.getSource()?.getFeatures().forEach((feature: Feature) => {
                    if (currentObjectId == feature.get('object_id')) {
                        feature.setStyle(highlightStyleRed);

                        const geometry = feature.getGeometry()

                        if (geometry) {
                            map.current?.getView().fit(geometry as SimpleGeometry, { duration: 500, maxZoom: 18 })
                            //map.current?.getView().animate({ center: calculateCenter(geometry as SimpleGeometry).center })
                        }

                    } else {
                        feature.setStyle(undefined); // Reset to default style
                    }
                })
            }

            if (linesLayer.current) {
                // Reset styles and apply highlight to matching features
                linesLayer.current.getSource()?.getFeatures().forEach((feature: Feature) => {
                    if (currentObjectId == feature.get('object_id')) {
                        feature.setStyle(highlightStyleRed);

                        const geometry = feature.getGeometry()
                        if (geometry) {
                            map.current?.getView().fit(geometry as SimpleGeometry, { duration: 500, maxZoom: 18 })
                        }
                    } else {
                        feature.setStyle(undefined); // Reset to default style
                    }
                })
            }
        }
    }, [currentObjectId])

    const { data: regionsData } = useSWR(`/general/regions/all`, (url) => fetcher(url, BASE_URL.ems), swrOptions)

    const { data: districtsData } = useSWR(selectedRegion ? `/general/districts/all?region_id=${selectedRegion}` : null, (url) => fetcher(url, BASE_URL.ems), swrOptions)

    const { data: searchData } = useSWR(throttledSearchObject !== "" && selectedDistrict && selectedYear ? `/general/search/objects?q=${throttledSearchObject}&id_city=${selectedDistrict}&year=${selectedYear}` : null, (url) => fetcher(url, BASE_URL.ems), swrOptions)

    const { data: figuresData, isValidating: figuresValidating } = useSWR(
        selectedDistrict && selectedYear ? `/gis/figures/all?city_id=${selectedDistrict}&year=${selectedYear}&offset=0&limit=${10000}` : null,
        (url) => axios.get(url, {
            baseURL: BASE_URL.ems
        }).then((res) => res.data),
        swrOptions
    )

    const { data: linesData, isValidating: linesValidating } = useSWR(
        !figuresValidating && selectedDistrict && selectedYear ? `/gis/lines/all?city_id=${selectedDistrict}&year=${selectedYear}&offset=0&limit=${10000}` : null,
        (url) => axios.get(url, {
            baseURL: BASE_URL.ems
        }).then((res) => {
            return res.data
        }),
        swrOptions
    )

    const { data: districtData } = useSWR(
        selectedDistrict ? `/gis/images/all?city_id=${selectedDistrict}` : null,
        (url) => axios.get(url, {
            baseURL: BASE_URL.ems
        }).then((res) => Array.isArray(res.data) ? res.data[0] : null),
        swrOptions
    )

    const [searchParams, setSearchParams] = useSearchParams()

    useEffect(() => {
        if (selectedRegion) {
            setSearchParams((params) => {
                params.set('r', selectedRegion.toString());
                return params
            })
        }

        if (selectedDistrict) {
            setSearchParams((params) => {
                params.set('d', selectedDistrict?.toString());
                return params
            })
        }

        if (selectedYear) {
            setSearchParams((params) => {
                params.set('y', selectedYear?.toString());
                return params
            })
        }

        if (currentObjectId) {
            setSearchParams((params) => {
                params.set('o', currentObjectId?.toString());
                return params
            })
        }
    }, [selectedRegion, selectedDistrict, selectedYear, currentObjectId, setSearchParams])

    useEffect(() => {
        if (Array.isArray(regionsData)) {
            const region = searchParams.get('r')

            if (searchParams.get('r')) {
                setSelectedRegion(Number(region))
            }
        }
    }, [searchParams, regionsData])

    useEffect(() => {
        if (Array.isArray(regionsData)) {
            const district = searchParams.get('d')

            if (Array.isArray(districtsData)) {
                if (district) {
                    setSelectedDistrict(Number(district))
                }
            }
        }
    }, [searchParams, regionsData, districtsData])


    useEffect(() => {
        if (Array.isArray(regionsData)) {
            const year = searchParams.get('y')

            if (year) {
                setSelectedYear(Number(year))
            }
        }
    }, [searchParams, regionsData])

    useEffect(() => {
        const object = searchParams.get('o')

        if (figuresData && linesData && object) {
            setCurrentObjectId(object)
        }
    }, [searchParams, figuresData, linesData])

    useEffect(() => {
        const districtBoundSource: VectorSource<Feature<Geometry>> | null = districtBoundLayer.current.getSource()

        if (selectedDistrict && districtBoundSource && districtBoundSource.getFeatures().length > 0) {
            const center: Coordinate = getCenter(districtBoundSource.getExtent())
            const settings = getCitySettings(selectedDistrict)

            if (Array.isArray(figuresData)) {
                figuresLayer.current.getSource()?.clear()
                if (figuresData.length > 0) {
                    figuresData.map((figure: IFigure) => {
                        processFigure(
                            figure,
                            settings.scale,
                            [center[0], center[1]],
                            figuresLayer
                        )
                    })

                    if (map.current) {
                        const extent = figuresLayer.current.getSource()?.getExtent()

                        if (extent) {
                            map.current.getView().fit(fromExtent(extent), { duration: 500 })
                        }
                    }
                }
            }

            if (Array.isArray(linesData)) {
                linesLayer.current.getSource()?.clear()
                if (linesData.length > 0) {
                    linesData.map((line: ILine) => {
                        processLine(line, settings.scale, [center[0], center[1]], linesLayer)
                    })
                }
            }
        }

    }, [figuresData, linesData, selectedDistrict, selectedYear, districtBoundLayer])

    useEffect(() => {
        if (!selectedRegion) {
            setSelectedDistrict(null)
            setSelectedYear(null)
        }
    }, [selectedRegion, selectedDistrict])

    useEffect(() => {
        if (selectedDistrict && districtData) {
            const settings = getCitySettings(selectedDistrict)

            const imageUrl = `${import.meta.env.VITE_API_EMS_URL}/static/${selectedDistrict}`;
            const img = new Image();
            img.src = imageUrl;
            img.onload = () => {
                if (map.current) {
                    console.log(districtData)

                    const width = img.naturalWidth
                    const height = img.naturalHeight
                    //const k = (width < height ? width / height : height / width)
                    const k = settings.image_scale

                    const wk = width * k
                    const hk = height * k

                    const center = [settings.offset_x + (wk), settings.offset_y - (hk)];

                    const extent = [
                        center[0] - (wk),
                        center[1] - (hk),
                        center[0] + (wk),
                        center[1] + (hk),
                    ];

                    // Set up the initial image layer with the extent
                    const imageSource = new ImageStatic({
                        url: imageUrl,
                        imageExtent: extent,
                    });
                    staticMapLayer.current.setSource(imageSource);

                    //map.current.addLayer(imageLayer.current);
                }
            };
        }
    }, [selectedDistrict, districtData])

    useEffect(() => {
        if (baseLayer.current) {
            baseLayer.current.on('prerender', function (e) {
                if (colorScheme === 'dark') {
                    if (e.context) {
                        const context = e.context as CanvasRenderingContext2D;
                        context.filter = 'grayscale(80%) invert(100%) hue-rotate(180deg) ';
                        context.globalCompositeOperation = 'source-over';
                    }
                } else {
                    if (e.context) {
                        const context = e.context as CanvasRenderingContext2D;
                        context.filter = 'none';
                    }
                }
            })

            baseLayer.current.on('postrender', function (e) {
                if (e.context) {
                    const context = e.context as CanvasRenderingContext2D;
                    context.filter = 'none';
                }
            })
        }
    }, [colorScheme])

    return (
        <Box w={'100%'} h='100%' pos={'relative'}>
            <Portal target='#header-portal'>
                <Flex gap={'sm'} direction={'row'}>
                    <Autocomplete
                        form='search_object'
                        placeholder="Поиск"
                        flex={'1'}
                        data={searchData ? searchData.map((item: { value: string, id_object: string }) => ({ label: item.value, value: item.id_object.toString() })) : []}
                        //onSelect={(e) => console.log(e.currentTarget.value)}
                        onChange={(value) => setSearchObject(value)}
                        onOptionSubmit={(value) => setCurrentObjectId(value)}
                        rightSection={
                            searchObject !== '' && (
                                <CloseButton
                                    size="sm"
                                    onMouseDown={(event) => event.preventDefault()}
                                    onClick={() => {
                                        setSearchObject('')
                                        //setSelectedCity(null)
                                    }}
                                    aria-label="Clear value"
                                />
                            )
                        }
                        leftSection={<IconSearch size={16} />}
                        value={searchObject}
                    />

                    <MantineSelect
                        placeholder="Регион"
                        flex={'1'}
                        data={regionsData ? regionsData.map((item: { name: string, id: number }) => ({ label: item.name, value: item.id.toString() })) : []}
                        onChange={(value) => setSelectedRegion(Number(value))}
                        clearable
                        onClear={() => {
                            setSelectedRegion(null)
                            setSearchParams((params) => {
                                params.delete('r')
                                return params
                            })
                        }}
                        searchable
                        value={selectedRegion ? selectedRegion.toString() : null}
                    />

                    <MantineSelect
                        placeholder="Населённый пункт"
                        flex={'1'}
                        data={districtsData ? districtsData.map((item: { name: string, id: number, district_name: string }) => ({ label: [item.name, item.district_name].join(' - '), value: item.id.toString() })) : []}
                        onChange={(value) => setSelectedDistrict(Number(value))}
                        clearable
                        onClear={() => {
                            setSelectedDistrict(null)
                            setSearchParams((params) => {
                                params.delete('d')
                                return params
                            })
                        }}
                        searchable
                        value={selectedDistrict ? selectedDistrict.toString() : null}
                    />

                    <MantineSelect
                        placeholder='Схема'
                        w='92px'
                        data={['2018', '2019', '2020', '2021', '2022', '2023', '2024'].map(el => ({ label: el, value: el }))}
                        onChange={(e) => {
                            if (e) {
                                setSelectedYear(Number(e))
                            } else {
                                setSelectedYear(null)
                            }
                        }}
                        onClear={() => {
                            setSelectedYear(null)
                            setSearchParams((params) => {
                                params.delete('y')
                                return params
                            })
                        }}
                        value={selectedYear ? selectedYear?.toString() : null}
                        clearable
                    />

                    <Button variant={alignMode ? 'filled' : 'transparent'} onClick={() => setAlignMode(!alignMode)}>
                        <IconBoxPadding style={{ width: rem(20), height: rem(20) }} />
                    </Button>

                    <Menu
                        position="bottom-end"
                        transitionProps={{ transition: 'pop-top-right' }}
                        withinPortal
                    >
                        <Menu.Target>
                            <Button variant='transparent'>
                                <Group gap={7} wrap='nowrap' style={{ flexShrink: 0 }} title='Слои'>
                                    <IconBoxMultiple style={{ width: rem(20), height: rem(20) }} />
                                    <IconChevronDown style={{ width: rem(12), height: rem(12) }} stroke={1.5} />
                                </Group>
                            </Button>
                        </Menu.Target>
                        <Menu.Dropdown miw={300}>
                            <Menu.Label>{'Настройка видимости слоёв'}</Menu.Label>

                            <Flex p='sm' direction='column' gap='xs'>
                                <Flex align='center' direction='row' gap='sm'>
                                    <MantineSelect
                                        value={satMapsProvider}
                                        data={[
                                            { label: 'Google', value: 'google' },
                                            { label: 'Яндекс', value: 'yandex' },
                                            { label: 'Подложка', value: 'custom' },
                                            { label: 'Static', value: 'static' }
                                        ]
                                        }
                                        onChange={(value) => setSatMapsProvider(value as SatelliteMapsProvider)}
                                    />
                                </Flex>
                                <Flex direction='row'>
                                    <ActionIcon size='lg' variant='transparent' onClick={() => submitOverlay()}>
                                        <IconUpload style={{ width: rem(20), height: rem(20) }} />
                                    </ActionIcon>

                                    <ActionIcon size='lg' variant='transparent' title='Добавить подложку'>
                                        <IconPlus style={{ width: rem(20), height: rem(20) }} />
                                    </ActionIcon>
                                </Flex>
                                <MapLayers map={map} />
                            </Flex>
                        </Menu.Dropdown>
                    </Menu>
                </Flex>
            </Portal>

            <LoadingOverlay visible={linesValidating || figuresValidating} />

            <Flex w={'100%'} h={'100%'} pos={'absolute'}>
                {selectedRegion && selectedDistrict && selectedYear &&
                    <MapToolbar
                        onSave={() => saveFeatures(drawingLayer)}
                        onRemove={() => draw.current?.removeLastPoint()}
                    />
                }

                {selectedRegion && selectedDistrict && selectedYear &&
                    <Flex direction='column' mah={'94%'} h={'100%'} pl='sm' style={{
                        ...mapControlsStyle,
                        maxWidth: '340px',
                        width: '100%',
                        top: '8px',
                        left: '8px',
                    }}>
                        <TabsPane defaultTab='objects' tabs={objectsPane} />
                        <Divider />
                        <TabsPane defaultTab='parameters' tabs={paramsPane} />
                    </Flex>
                }

                <MapStatusbar
                    mapControlsStyle={mapControlsStyle}
                />
            </Flex>

            <Flex
                id="map-container"
                ref={mapElement}
                style={{
                    width: '100%',
                    height: '100%',
                    maxHeight: '100%',
                    position: 'absolute',
                    flexGrow: 1
                }}
            >
                <div ref={tooltipRef}></div>
            </Flex>
        </Box >
    );
};

export default MapComponent
