import '@geoman-io/maplibre-geoman-free/dist/maplibre-geoman.css';
import 'maplibre-gl/dist/maplibre-gl.css';

import React, {
    useCallback,
    useEffect,
    useMemo,
    useRef,
    useState,
} from 'react';

import ml from 'maplibre-gl';

import { GeoRegionGType } from '@/api/types.ts';
import {
    FeatureData,
    GeoJsonImportFeature,
    Geoman,
} from '@geoman-io/maplibre-geoman-free';

import type {
    GmEvent,
    GmEventData,
} from './types.ts';

const demoFeatures: Array<GeoJsonImportFeature> = [];


const mapStyle: ml.StyleSpecification = {
    version: 8,
    sources: {
        osm: {
            type: 'raster',
            tiles: [
                'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
            ],
            tileSize: 256,
            attribution:
                '',
        },
    },
    layers: [
        {
            id: 'osm',
            type: 'raster',
            source: 'osm',
        },
    ],
}

interface GmMapProps {
    height: number;
    onlyView?: boolean;
    values?: GeoRegionGType[] | null;
    onChange: (value: GeoRegionGType[]) => void;
}

const getGmOptions = (onlyView: boolean = false) => ({
    controls: {
        draw: {
            //"marker", "circle", "circle_marker", "ellipse", "text_marker", "line", "rectangle", "polygon", "freehand", "custom_shape"
            polygon: {
                uiEnabled: !onlyView,
                active: false,
            },
            rectangle: {
                uiEnabled: false,
            },
            circle: {
                uiEnabled: false,
            },
            circle_marker: {
                uiEnabled: false,
            },
            ellipse: {
                uiEnabled: false,
            },
            text_marker: {
                uiEnabled: false,
            },
            line: {
                uiEnabled: false,
            },
            marker: {
                uiEnabled: false,
            },
            freehand: {
                uiEnabled: false,
            },
            custom_shape: {
                uiEnabled: false,
            },
        },
        edit: {
            drag: {
                uiEnabled: !onlyView,
            },
            change: {
                uiEnabled: !onlyView,
            },
            rotate: {
                uiEnabled: !onlyView,
            },
            scale: {
                uiEnabled: !onlyView,
            },
            copy: {
                uiEnabled: !onlyView,
            },
            cut: {
                uiEnabled: !onlyView,
            },
            split: {
                uiEnabled: !onlyView,
            },
            union: {
                uiEnabled: !onlyView,
            },
            difference: {
                uiEnabled: !onlyView,
            },
            line_simplification: {
                uiEnabled: !onlyView,
            },
            lasso: {
                uiEnabled: !onlyView,
            },
            delete: {
                uiEnabled: !onlyView,
            },
        },
        helper: {
            snapping: {
                uiEnabled: !onlyView,
                active: !onlyView,
            },
        },
    },
});


const GmMap: React.FC<GmMapProps> = (props: GmMapProps) => {
    const mapRef = useRef<HTMLDivElement>(null);
    const mapInstance = useRef<ml.Map | null>(null);
    const geomanInstance = useRef<Geoman | null>(null);

    const gmOptions = useMemo(() => getGmOptions(props.onlyView), [props.onlyView]);

    const [gmEvents, setGmEvents] = useState<GmEventData[]>([]);

    const getGeoJson = (featureData: FeatureData) => {
        try {
            return JSON.stringify(featureData.getGeoJson(), null, 2);
        } catch (error) {
            return `Can't retrieve GeoJSON: ${error}`;
        }
    };



    useEffect(() => {
        if (props.onlyView) {

            loadValuesShapes();

        }
    }, [props.values]);



    const handleEvent = useCallback((event: GmEvent) => {
        console.log('Event', event.name);

        if (event.name) {
            const eventForUpdateData = ['gm:create', 'gm:edit', 'gm:remove'];
            if (eventForUpdateData.includes(event.name as string)) {
                getApiGeoJsonInMap();
            }
        }


    }, []);

    const getApiGeoJsonInMap = () => {

        console.log('----> Get Api GeoJson In Map');

        let geoJson = geomanInstance.current!.features.exportGeoJson();

        console.log('----> GeoJson', geoJson);
        let data: GeoRegionGType[] = [];
        geoJson.features.forEach((feature) => {
            if (feature.geometry.type === 'Polygon') {

                data.push({
                    geometry: {
                        type: 'Polygon',
                        coordinates: feature.geometry.coordinates,
                    },
                });

            }

            if (feature.geometry.type === 'MultiPolygon') {
                data.push({
                    geometry: {
                        type: 'Polygon',
                        coordinates: feature.geometry.coordinates[0],
                    },
                });

            }
        });

        props.onChange(data);
        console.log('----> Data', data);


    }

    // Функция для фокусировки камеры на всех полигонах
    // Использование: zoomToFeatures()
    const zoomToFeatures = useCallback(() => {
        if (!geomanInstance.current || !mapInstance.current) {
            return;
        }


        try {
            // Получаем все фичи
            const geoJson = geomanInstance.current.features.exportGeoJson();

            // Проверяем, есть ли фичи
            if (!geoJson.features || geoJson.features.length === 0) {
                console.log('No features to zoom to');
                return;
            }

            // Вычисляем bounding box вручную из координат всех фичей
            let minLng = Infinity;
            let minLat = Infinity;
            let maxLng = -Infinity;
            let maxLat = -Infinity;

            geoJson.features.forEach((feature) => {
                const coords = feature.geometry.coordinates;

                // Обрабатываем разные типы геометрии
                let coordinates: number[][][] = [];
                if (feature.geometry.type === 'Polygon') {
                    coordinates = coords as number[][][];
                } else if (feature.geometry.type === 'MultiPolygon') {
                    coordinates = (coords as number[][][][]).flat();
                }

                coordinates.forEach((ring) => {
                    ring.forEach((coord) => {
                        const [lng, lat] = coord;
                        minLng = Math.min(minLng, lng);
                        minLat = Math.min(minLat, lat);
                        maxLng = Math.max(maxLng, lng);
                        maxLat = Math.max(maxLat, lat);
                    });
                });
            });

            // Проверяем, что bounds валидны
            if (minLng !== Infinity && minLat !== Infinity && maxLng !== -Infinity && maxLat !== -Infinity) {
                const bounds: [[number, number], [number, number]] = [
                    [minLng, minLat],
                    [maxLng, maxLat]
                ];

                // Проверяем, что bounds не нулевые
                if (minLng !== maxLng || minLat !== maxLat) {
                    mapInstance.current.fitBounds(bounds, { padding: 50 });
                }
            }
        } catch (error) {
            console.error('Error zooming to features:', error);
        }
    }, []);


    const loadValuesShapes = () => {
        if (!geomanInstance.current) {
            console.warn('Geoman not loaded yet');
            return;
        }

        //Удаляем все фичи
        geomanInstance.current!.features.deleteAll();

        props.values?.forEach((shape) => {

            let geoJson: GeoJsonImportFeature = {
                type: 'Feature',
                properties: {
                    shape: 'polygon',
                },
                geometry: {
                    type: 'Polygon',
                    coordinates: shape.geometry?.coordinates as any
                },
            }
            console.log('GeoJson', geoJson);

            geomanInstance.current!.features.importGeoJsonFeature(geoJson);
        });


        setTimeout(() => {
            zoomToFeatures();
        }, 1000);



    };

    useEffect(() => {
        if (mapRef.current) {
            const map = new ml.Map({
                style: mapStyle,
                container: mapRef.current,

                //Москва
                center: [37.6156, 55.7558],
                zoom: 5,
                fadeDuration: 50,

            });

            mapInstance.current = map;
            const geoman = new Geoman(map, gmOptions);
            geomanInstance.current = geoman;



            map.on('gm:loaded', () => {
                console.log('Geoman loaded', geoman);

                // Если режим только просмотра - отключаем все режимы редактирования
                if (props.onlyView) {
                    geoman.disableAllModes();
                }

                // Load demo shapes
                loadValuesShapes();
            });


            // Mode events
            map.on('gm:globaldrawmodetoggled', handleEvent);
            map.on('gm:globaleditmodetoggled', handleEvent);
            map.on('gm:globalremovemodetoggled', handleEvent);
            map.on('gm:globalrotatemodetoggled', handleEvent);
            map.on('gm:globaldragmodetoggled', handleEvent);
            map.on('gm:globalcutmodetoggled', handleEvent);
            map.on('gm:globalsnappingmodetoggled', handleEvent);

            // Drawing events
            // map.on('gm:draw', handleEvent); // Enable to listen to all draw events
            map.on('gm:create', handleEvent);

            // Edit events
            // map.on('gm:edit', handleEvent); // Enable to listen to all edit events
            map.on('gm:editstart', handleEvent);
            map.on('gm:editend', handleEvent);

            // Remove events
            map.on('gm:remove', handleEvent);

            // Rotate events
            // map.on('gm:rotate', handleEvent); // Enable to listen to all rotate events
            map.on('gm:rotatestart', handleEvent);
            map.on('gm:rotateend', handleEvent);

            // Drag events
            // map.on('gm:drag', handleEvent); // Enable to listen to all drag events
            map.on('gm:dragstart', handleEvent);
            map.on('gm:dragend', handleEvent);

            // Cut events
            map.on('gm:cut', handleEvent);

            // Helper and control events
            map.on('gm:helper', handleEvent);
            map.on('gm:control', handleEvent);
        }

        return () => {
            if (mapInstance.current) {
                mapInstance.current.remove();
            }
        };
    }, [handleEvent, props.onlyView]);

    return (
        <div

            className={props.onlyView ? 'hide-geoman-controls' : ''}
            ref={mapRef} style={{

                width: '100%',
                height: props.height

            }}>
            {/* MapLibre Geoman container */}
        </div>
    );
};

export default GmMap;