import { useCallback, useEffect, useRef, useState } from 'react'
import GeoJSON from 'ol/format/GeoJSON'
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, XYZ } from 'ol/source'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
import { Divider, IconButton, Slider, Stack, Select as MUISelect, MenuItem, Box, Typography, Drawer, Button, Modal, Accordion, AccordionSummary, AccordionDetails, SxProps, Theme } from '@mui/material'
import { Add, Adjust, Api, CircleOutlined, ExpandMore, OpenWith, RectangleOutlined, Straighten, Timeline, Undo, Upload, Warning } from '@mui/icons-material'
import Geometry, { Type } from 'ol/geom/Geometry'
import { click, never, noModifierKeys, platformModifierKeyOnly, primaryAction, shiftKeyOnly } from 'ol/events/condition'
import Feature from 'ol/Feature'
import { SatelliteMapsProvider } from '../../interfaces/map'
import { containsExtent, Extent, getCenter, getHeight, getWidth } from 'ol/extent'
import { drawingLayerStyle, regionsLayerStyle, selectStyle } from './MapStyles'
import { googleMapsSatelliteSource, regionsLayerSource, yandexMapsSatelliteSource } from './MapSources'
import { mapCenter } from './MapConstants'
import ImageLayer from 'ol/layer/Image'
import VectorImageLayer from 'ol/layer/VectorImage'
import { LineString, MultiPoint, Point, Polygon, SimpleGeometry } from 'ol/geom'
import { fromExtent } from 'ol/geom/Polygon'
import Collection from 'ol/Collection'
import { Coordinate } from 'ol/coordinate'
import { Stroke, Fill, Circle as CircleStyle, Style } from 'ol/style'
import { calculateExtent, calculateRotationAngle, rotateProjection } from './mapUtils'
import MapBrowserEvent from 'ol/MapBrowserEvent'
import { fromLonLat, get } from 'ol/proj'
import { useCities } from '../../hooks/swrHooks'
import useSWR from 'swr'
import { fetcher } from '../../http/axiosInstance'
import { BASE_URL } from '../../constants'

const MapComponent = () => {
    const { cities } = useCities(100, 1)

    useEffect(() => {
        if (cities) {
            cities.map((city: any) => {
                citiesLayer.current?.getSource()?.addFeature(new Feature(new Point(fromLonLat([city.longitude, city.width]))))
            })
        }
    }, [cities])

    const [currentCoordinate, setCurrentCoordinate] = useState<Coordinate | null>(null)
    const [currentZ, setCurrentZ] = useState<number | undefined>(undefined)
    const [currentX, setCurrentX] = useState<number | undefined>(undefined)
    const [currentY, setCurrentY] = useState<number | undefined>(undefined)

    const [file, setFile] = useState(null)
    const [polygonExtent, setPolygonExtent] = useState<Extent | undefined>(undefined)
    const [bottomLeft, setBottomLeft] = useState<Coordinate | undefined>(undefined)
    const [topLeft, setTopLeft] = useState<Coordinate | undefined>(undefined)
    const [topRight, setTopRight] = useState<Coordinate | undefined>(undefined)
    const [bottomRight, setBottomRight] = useState<Coordinate | undefined>(undefined)

    const mapElement = useRef<HTMLDivElement | null>(null)
    const [currentTool, setCurrentTool] = useState<Type | null>(null)

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

    const [satMapsProvider, setSatMapsProvider] = useState<SatelliteMapsProvider>('custom')

    const gMapsSatSource = useRef<XYZ>(googleMapsSatelliteSource)

    const customMapSource = useRef<XYZ>(new XYZ({
        url: `${import.meta.env.VITE_API_EMS_URL}/tile/custom/{z}/{x}/{y}`,
        attributions: 'Custom map data'
    }))

    const yMapsSatSource = useRef<XYZ>(yandexMapsSatelliteSource)

    const satLayer = useRef<TileLayer>(new TileLayer({
        source: gMapsSatSource.current,
    }))

    const draw = useRef<Draw | null>(null)
    const snap = useRef<Snap | 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()
    }))

    const regionsLayer = useRef<VectorImageLayer>(new VectorImageLayer({
        source: regionsLayerSource,
        style: regionsLayerStyle
    }))

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

    const baseLayer = useRef<TileLayer>(new TileLayer({
        source: new OSM(),
    }))

    const imageLayer = useRef<ImageLayer<ImageStatic>>(new ImageLayer())

    const addInteractions = () => {
        if (currentTool) {
            draw.current = new Draw({
                source: drawingLayerSource.current,
                type: currentTool,
                condition: noModifierKeys
            })

            draw.current.on('drawend', function (s) {
                console.log(s.feature.getGeometry()?.getType())
                let type = 'POLYGON'

                switch (s.feature.getGeometry()?.getType()) {
                    case 'LineString':
                        type = 'LINE'
                    case 'Polygon':
                        type = 'POLYGON'
                }
                const coordinates = (s.feature.getGeometry() as SimpleGeometry).getCoordinates()
                uploadCoordinates(coordinates, type)
            })

            map?.current?.addInteraction(draw.current)
            snap.current = new Snap({ source: drawingLayerSource.current })
            map?.current?.addInteraction(snap.current)
        }
    }

    // Function to save features to localStorage
    const saveFeatures = () => {
        const features = drawingLayer.current?.getSource()?.getFeatures()
        if (features && features.length > 0) {
            const geoJSON = new GeoJSON()
            const featuresJSON = geoJSON.writeFeatures(features)
            localStorage.setItem('savedFeatures', featuresJSON)
        }

        console.log(drawingLayer.current?.getSource()?.getFeatures())
    }

    // Function to load features from localStorage
    const loadFeatures = () => {
        const savedFeatures = localStorage.getItem('savedFeatures')
        if (savedFeatures) {
            const geoJSON = new GeoJSON()
            const features = geoJSON.readFeatures(savedFeatures, {
                featureProjection: 'EPSG:4326', // Ensure the projection is correct
            })
            drawingLayerSource.current?.addFeatures(features)  // Add features to the vector source
            //drawingLayer.current?.getSource()?.changed()
        }
    }

    const handleToolSelect = (tool: Type) => {
        if (currentTool == tool) {
            setCurrentTool(null)
        } else {
            setCurrentTool(tool)
        }
    }

    const zoomToFeature = (feature: Feature) => {
        const geometry = feature.getGeometry()
        const extent = geometry?.getExtent()

        if (map.current && extent) {
            map.current.getView().fit(extent, {
                duration: 300,
                maxZoom: 19,
            })
        }
    }

    const style = new Style({
        geometry: function (feature) {
            const modifyGeometry = feature.get('modifyGeometry');
            return modifyGeometry ? modifyGeometry.geometry : feature.getGeometry();
        },
        fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)',
        }),
        stroke: new Stroke({
            color: '#ffcc33',
            width: 2,
        }),
        image: new CircleStyle({
            radius: 7,
            fill: new Fill({
                color: '#ffcc33',
            }),
        }),
    });

    function calculateCenter(geometry: SimpleGeometry) {
        let center, coordinates, minRadius;
        const type = geometry.getType();
        if (type === 'Polygon') {
            let x = 0;
            let y = 0;
            let i = 0;
            coordinates = (geometry as Polygon).getCoordinates()[0].slice(1);
            coordinates.forEach(function (coordinate) {
                x += coordinate[0];
                y += coordinate[1];
                i++;
            });
            center = [x / i, y / i];
        } else if (type === 'LineString') {
            center = (geometry as LineString).getCoordinateAt(0.5);
            coordinates = geometry.getCoordinates();
        } else {
            center = getCenter(geometry.getExtent());
        }
        let sqDistances;
        if (coordinates) {
            sqDistances = coordinates.map(function (coordinate: Coordinate) {
                const dx = coordinate[0] - center[0];
                const dy = coordinate[1] - center[1];
                return dx * dx + dy * dy;
            });
            minRadius = Math.sqrt(Math.max.apply(Math, sqDistances)) / 3;
        } else {
            minRadius =
                Math.max(
                    getWidth(geometry.getExtent()),
                    getHeight(geometry.getExtent()),
                ) / 3;
        }
        return {
            center: center,
            coordinates: coordinates,
            minRadius: minRadius,
            sqDistances: sqDistances,
        };
    }

    const handleImageDrop = useCallback((event: any) => {
        event.preventDefault();
        event.stopPropagation();

        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)
                                    }
                                }
                            });

                            // Function to update the image layer with a new source when extent changes
                            const updateImageSource = () => {
                                const newExtent = polygonFeature.getGeometry()?.getExtent();

                                const bottomLeft = polygonFeature.getGeometry()?.getCoordinates()[0][0]
                                const topLeft = polygonFeature.getGeometry()?.getCoordinates()[0][1]
                                const topRight = polygonFeature.getGeometry()?.getCoordinates()[0][2]
                                const bottomRight = polygonFeature.getGeometry()?.getCoordinates()[0][3]

                                setPolygonExtent(newExtent)
                                setBottomLeft(bottomLeft)
                                setTopLeft(topLeft)
                                setTopRight(topRight)
                                setBottomRight(bottomRight)

                                if (newExtent && bottomLeft && bottomRight && topRight && topLeft) {
                                    const originalExtent = calculateExtent(bottomLeft, topLeft, topRight, bottomRight)

                                    const worldExtent = get('EPSG:3857')?.getExtent() as Extent
                                    const zoomLevel = Number(map.current?.getView().getZoom()?.toFixed(0))
                                    const { tileX: blX, tileY: blY } = getGridCellPosition(bottomLeft[0], bottomLeft[1], worldExtent, zoomLevel)
                                    const { tileX: tlX, tileY: tlY } = getGridCellPosition(topLeft[0], topLeft[1], worldExtent, zoomLevel)
                                    const { tileX: trX, tileY: trY } = getGridCellPosition(topRight[0], topRight[1], worldExtent, zoomLevel)
                                    const { tileX: brX, tileY: brY } = getGridCellPosition(bottomRight[0], topRight[1], worldExtent, zoomLevel)
                                    const minX = Math.min(blX, tlX, trX, brX)
                                    const maxX = Math.max(blX, tlX, trX, brX)
                                    const minY = Math.min(blY, tlY, trY, brY)
                                    const maxY = Math.max(blY, tlY, trY, brY)

                                    const mapWidth = Math.abs(worldExtent[0] - worldExtent[2])
                                    const mapHeight = Math.abs(worldExtent[1] - worldExtent[3])

                                    const tilesH = Math.sqrt(Math.pow(4, zoomLevel))
                                    const tileWidth = mapWidth / (Math.sqrt(Math.pow(4, zoomLevel)))
                                    const tileHeight = mapHeight / (Math.sqrt(Math.pow(4, zoomLevel)))

                                    let minPosX = minX - (tilesH / 2)
                                    let maxPosX = maxX - (tilesH / 2) + 1
                                    let minPosY = -(minY - (tilesH / 2))
                                    let maxPosY = -(maxY - (tilesH / 2) + 1)
                                    console.log(`tileWidth: ${tileWidth} minPosX: ${minPosX} maxPosX: ${maxPosX} minPosY: ${minPosY} maxPosY: ${maxPosY}`)

                                    const newMinX = tileWidth * minPosX
                                    const newMaxX = tileWidth * maxPosX
                                    const newMinY = tileHeight * maxPosY
                                    const newMaxY = tileHeight * minPosY

                                    console.log('Tile slippy bounds: ', minX, maxX, minY, maxY)
                                    console.log('Tile bounds: ', newMinX, newMaxX, newMinY, newMaxY)

                                    const angleDegrees = calculateRotationAngle(bottomLeft, bottomRight) * 180 / Math.PI

                                    const paddingLeft = Math.abs(newExtent[0] - newMinX)
                                    const paddingRight = Math.abs(newExtent[2] - newMaxX)
                                    const paddingTop = Math.abs(newExtent[3] - newMaxY)
                                    const paddingBottom = Math.abs(newExtent[1] - newMinY)

                                    const pixelWidth = Math.abs(minX - (maxX + 1)) * 256
                                    const pixelHeight = Math.abs(minY - (maxY + 1)) * 256

                                    const width = Math.abs(newMinX - newMaxX)
                                    const perPixel = width / pixelWidth

                                    const paddingLeftPixel = paddingLeft / perPixel
                                    const paddingRightPixel = paddingRight / perPixel
                                    const paddingTopPixel = paddingTop / perPixel
                                    const paddingBottomPixel = paddingBottom / perPixel

                                    console.log('Rotation angle degrees: ', angleDegrees)

                                    console.log('Padding top pixel: ', paddingTopPixel)
                                    console.log('Padding left pixel: ', paddingLeftPixel)
                                    console.log('Padding right pixel: ', paddingRightPixel)
                                    console.log('Padding bottom pixel: ', paddingBottomPixel)

                                    console.log('Per pixel: ', width / pixelWidth)

                                    const boundsWidthPixel = Math.abs(newExtent[0] - newExtent[2]) / perPixel
                                    const boundsHeightPixel = Math.abs(newExtent[1] - newExtent[3]) / perPixel
                                    console.log('Bounds width pixel', boundsWidthPixel)
                                    console.log('Bounds height pixel', boundsHeightPixel)

                                    // Result will be sharp rotate(angleDegrees), resize(boundsWidthPixel), extend()

                                    const newImageSource = new ImageStatic({
                                        url: imageUrl,
                                        imageExtent: originalExtent,
                                        projection: rotateProjection('EPSG:3857', calculateRotationAngle(bottomLeft, bottomRight), originalExtent)
                                    });
                                    imageLayer.current.setSource(newImageSource);
                                }
                            };

                            translate.on('translateend', updateImageSource);
                            //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()
                            })

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

    function regionsInit() {
        map.current?.on('click', function (e) {
            if (selectedRegion.current !== null) {
                selectedRegion.current = null
            }

            if (map.current) {
                map.current.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
                    if (layer === regionsLayer.current) {
                        selectedRegion.current = feature as Feature
                        // Zoom to the selected feature
                        zoomToFeature(selectedRegion.current)

                        return true
                    } else return false
                });
            }
        })

        // Show current selected region
        map.current?.on('pointermove', function (e) {
            if (selectedRegion.current !== null) {
                selectedRegion.current.setStyle(undefined)
                selectedRegion.current = null
            }

            if (map.current) {
                map.current.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
                    if (layer === regionsLayer.current) {
                        selectedRegion.current = feature as Feature
                        selectedRegion.current.setStyle(selectStyle)

                        if (feature.get('district')) {
                            setStatusText(feature.get('district'))
                        }

                        return true
                    } else return false
                })
            }
        })

        // Hide regions layer when fully visible
        map.current?.on('moveend', function () {
            const viewExtent = map.current?.getView().calculateExtent(map.current.getSize())
            const features = regionsLayer.current.getSource()?.getFeatures()

            let isViewCovered = false

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

            regionsLayer.current.setVisible(!isViewCovered)
        })
    }

    function getTilesPerSide(zoom: number) {
        return Math.pow(2, zoom)
    }

    function normalize(value: number, min: number, max: number) {
        return (value - min) / (max - min)
    }

    function getTileIndex(normalized: number, tilesPerSide: number) {
        return Math.floor(normalized * tilesPerSide)
    }

    function getGridCellPosition(x: number, y: number, extent: Extent, zoom: number) {
        const tilesPerSide = getTilesPerSide(zoom);
        const minX = extent[0]
        const minY = extent[1]
        const maxX = extent[2]
        const maxY = extent[3]

        // Normalize the coordinates
        const xNormalized = normalize(x, minX, maxX);
        const yNormalized = normalize(y, minY, maxY);

        // Get tile indices
        const tileX = getTileIndex(xNormalized, tilesPerSide);
        const tileY = getTileIndex(1 - yNormalized, tilesPerSide);

        return { tileX, tileY };
    }

    useEffect(() => {
        drawingLayer.current = new VectorLayer({
            source: drawingLayerSource.current,
            style: drawingLayerStyle
        })

        overlayLayer.current = new VectorLayer({
            source: overlayLayerSource.current,
            style: function (feature) {
                const styles = [style]
                const modifyGeometry = feature.get('modifyGeometry')
                const geometry = modifyGeometry ? modifyGeometry.geometry : feature.getGeometry()
                const result = calculateCenter(geometry)
                const center = result.center
                if (center) {
                    styles.push(
                        new Style({
                            geometry: new Point(center),
                            image: new CircleStyle({
                                radius: 4,
                                fill: new Fill({
                                    color: '#ff3333'
                                })
                            })
                        })
                    )
                    const coordinates = result.coordinates
                    if (coordinates) {
                        const minRadius = result.minRadius
                        const sqDistances = result.sqDistances
                        const rsq = minRadius * minRadius
                        if (Array.isArray(sqDistances)) {
                            const points = coordinates.filter(function (coordinate, index) {
                                return sqDistances[index] > rsq
                            })
                            styles.push(
                                new Style({
                                    geometry: new MultiPoint(points),
                                    image: new CircleStyle({
                                        radius: 4,
                                        fill: new Fill({
                                            color: '#33cc33'
                                        })
                                    })
                                })
                            )
                        }
                    }
                }
                return styles
            },
        })

        nodeLayer.current = new VectorLayer({
            source: nodeLayerSource.current,
            style: drawingLayerStyle
        })

        map.current = new Map({
            controls: [],
            layers: [baseLayer.current, satLayer.current, regionsLayer.current, citiesLayer.current, drawingLayer.current, imageLayer.current, overlayLayer.current, nodeLayer.current],
            target: mapElement.current as HTMLDivElement,
            view: new View({
                center: mapCenter,//center: fromLonLat([130.401113, 67.797368]),
                zoom: 16,
                maxZoom: 21,
                //extent: mapExtent,
            }),
        })

        map.current.on('pointermove', function (e: MapBrowserEvent<any>) {
            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 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()

        regionsInit()

        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()
        } else {
            if (draw.current) map?.current?.removeInteraction(draw.current)
            if (snap.current) map?.current?.removeInteraction(snap.current)
        }
    }, [currentTool])

    const uploadCoordinates = async (coordinates: any, type: any) => {
        try {
            const response = await fetch(`${import.meta.env.VITE_API_EMS_URL}/nodes`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ coordinates, object_id: 1, type: type }) // Replace with actual object_id
            });

            if (response.ok) {
                const data = await response.json();
                console.log('Node created:', data);
            } else {
                console.error('Failed to upload coordinates');
            }
        } catch (error) {
            console.error('Error:', error);
        }
    };

    const [satelliteOpacity, setSatelliteOpacity] = useState<number>(0)

    const [statusText, setStatusText] = useState('')

    // Visibility setting
    useEffect(() => {
        satLayer.current?.setOpacity(satelliteOpacity)

        if (satelliteOpacity == 0) {
            baseLayer.current?.setVisible(true)
            satLayer.current?.setVisible(false)
        } if (satelliteOpacity == 1) {
            baseLayer.current?.setVisible(false)
            satLayer.current?.setVisible(true)
        } else if (satelliteOpacity > 0 && satelliteOpacity < 1) {
            baseLayer.current?.setVisible(true)
            satLayer.current?.setVisible(true)
        }
    }, [satelliteOpacity])

    // Satellite tiles setting
    useEffect(() => {
        satLayer.current?.setSource(satMapsProvider == 'google' ? gMapsSatSource.current : satMapsProvider == 'yandex' ? yMapsSatSource.current : satMapsProvider == 'custom' ? customMapSource.current : gMapsSatSource.current)
        satLayer.current?.getSource()?.refresh()
    }, [satMapsProvider])

    const submitOverlay = async () => {
        if (file && polygonExtent && bottomLeft && topLeft && topRight && bottomRight) {
            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', bottomLeft[0].toString())
            formData.append('blY', bottomLeft[1].toString())
            formData.append('tlX', topLeft[0].toString())
            formData.append('tlY', topLeft[1].toString())
            formData.append('trX', topRight[0].toString())
            formData.append('trY', topRight[1].toString())
            formData.append('brX', bottomRight[0].toString())
            formData.append('brY', bottomRight[1].toString())

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

    const mapControlsStyle: SxProps<Theme> = {
        borderRadius: '4px',
        position: 'absolute',
        zIndex: '1',
        backgroundColor: (theme) =>
            theme.palette.mode === 'light'
                ? '#FFFFFFAA'
                : '#000000AA',
        backdropFilter: 'blur(8px)'
    }

    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') {
                    let coordinates: Coordinate[] = []
                    if (Array.isArray(node.shape)) {
                        node.shape.map((point: any) => {
                            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])

    return (
        <Box height={'calc(100% - 64px)'} maxHeight={'100%'} flex={'1'} flexGrow={'1'} position={'relative'}>
            <Stack
                direction={'column'}
                sx={{
                    ...mapControlsStyle,
                    top: '8px',
                    right: '8px',
                }}
                divider={<Divider orientation='horizontal' flexItem />}>
                <IconButton onClick={() => {
                    fetch(`${import.meta.env.VITE_API_EMS_URL}/hello`, { method: 'GET' }).then(res => console.log(res))
                }}>
                    <Api />
                </IconButton>

                <IconButton onClick={() => {
                    saveFeatures()
                }}>
                    <Warning />
                </IconButton>

                <IconButton
                    onClick={() => {
                        draw.current?.removeLastPoint()
                    }}>
                    <Undo />
                </IconButton>

                <IconButton
                    sx={{ backgroundColor: currentTool === 'Point' ? 'Highlight' : 'transparent' }}
                    onClick={() => handleToolSelect('Point')}>
                    <Adjust />
                </IconButton>

                <IconButton
                    sx={{ backgroundColor: currentTool === 'LineString' ? 'Highlight' : 'transparent' }}
                    onClick={() => handleToolSelect('LineString')}>
                    <Timeline />
                </IconButton>

                <IconButton
                    sx={{ backgroundColor: currentTool === 'Polygon' ? 'Highlight' : 'transparent' }}
                    onClick={() => handleToolSelect('Polygon')}>
                    <RectangleOutlined />
                </IconButton>

                <IconButton
                    sx={{ backgroundColor: currentTool === 'Circle' ? 'Highlight' : 'transparent' }}
                    onClick={() => handleToolSelect('Circle')}>
                    <CircleOutlined />
                </IconButton>

                <IconButton
                    onClick={() => map?.current?.addInteraction(new Translate())}
                >
                    <OpenWith />
                </IconButton>

                <IconButton>
                    <Straighten />
                </IconButton>
            </Stack>

            <Stack
                direction={'column'}
                sx={{
                    ...mapControlsStyle,
                    maxWidth: '300px',
                    width: '100%',
                    top: '8px',
                    left: '8px',
                }} divider={<Divider orientation='horizontal' flexItem />}
            >
                <Stack direction={'row'}>
                    <IconButton onClick={() => submitOverlay()}>
                        <Upload />
                    </IconButton>

                    <IconButton title='Добавить подложку'>
                        <Add />
                    </IconButton>
                </Stack>


                <Stack direction={'row'} padding={'8px'} spacing={4}>
                    <Slider size='small' aria-label="Opacity" min={0} max={1} step={0.001} defaultValue={satelliteOpacity} value={satelliteOpacity} onChange={(_, value) => setSatelliteOpacity(Array.isArray(value) ? value[0] : value)} />

                    <MUISelect
                        variant='standard'
                        labelId="demo-simple-select-label"
                        id="demo-simple-select"
                        value={satMapsProvider}
                        label="Satellite Provider"
                        onChange={(e) => setSatMapsProvider(e.target.value as SatelliteMapsProvider)}
                    >
                        <MenuItem value={'google'}>Google</MenuItem>
                        <MenuItem value={'yandex'}>Яндекс</MenuItem>
                        <MenuItem value={'custom'}>Custom</MenuItem>
                    </MUISelect>
                </Stack>

                <Accordion disableGutters sx={{ backgroundColor: 'transparent' }} defaultExpanded>
                    <AccordionSummary
                        expandIcon={<ExpandMore />}
                        aria-controls="panel1-content"
                        id="panel1-header"
                    >
                        <Typography>Объекты</Typography>
                    </AccordionSummary>
                    <AccordionDetails>
                        <Typography>
                            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
                            malesuada lacus ex, sit amet blandit leo lobortis eget.
                        </Typography>
                    </AccordionDetails>
                </Accordion>

            </Stack>

            <Stack direction={'row'}
                sx={{
                    ...mapControlsStyle,
                    bottom: '8px',
                    left: '8px',
                }}

                divider={<Divider orientation='vertical' flexItem />}
            >
                <Stack>
                    <Typography>
                        x: {currentCoordinate?.[0]}
                    </Typography>
                    <Typography>
                        y: {currentCoordinate?.[1]}
                    </Typography>
                </Stack>

                <Typography>
                    Z={currentZ}
                    X={currentX}
                    Y={currentY}
                </Typography>
            </Stack>

            <Stack direction={'row'}
                sx={{
                    ...mapControlsStyle,
                    bottom: '8px',
                    right: '8px',
                }}

                divider={<Divider orientation='vertical' flexItem />}>
                <Stack>
                    {statusText}
                </Stack>
            </Stack>

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

export default MapComponent
