/*
* @author: chensk
* @updateTime: 2026-4-14 16:56
*/

// mapbox-native.js
import {
    base_sources,LayerConfig,
    business_sources, business_layers,
    Dark_Sources, Light_Sources,
    Dark_Layers, Light_Layers,
    Vector_Layers, Image_Layers,
} from "../../baseSetting/gis-data/sources_layers";

/**
 * 地图配置文件
 */
const mapConfig = {
    noMap: false,
    mapUrl: 'https://geoserver.yw.hc-yun.com',      // 离线地图根目录
    mapUrl2: 'http://36.133.23.184:18090', // 外网地图根目录
    workspace: 'mango',   // 地图服务的工作空间
    map_srid: 'EPSG:3857', // 底图坐标系
    business_srid: 'EPSG:3857', // 覆盖物坐标系
    isOnline: true,

    minZoom: 5,  // 最小缩放层级 4.75
    maxZoom: 17, // 最大文件服务器缩放层级
    maxOnlineZoom: 22, // 最大在线地图缩放层级
    zoom: 10,  // 默认缩放层级

    pitch: 0,  // 仰角
    bearing: 0, // 方位角
    mapExtent:   [73.55, 3.85, 135.08, 53.55],  // [西, 南, 东, 北]

    center: [121.91946010684916, 30.9085305399487], // 中心点 {lng: 111.61666756532281, lat: 30.35533711534265}
}

/**
 * 开发环境2D/2.5D底图配置
 */
const DevMapConfig = {
    projection_from: 'gcj02',
    projection_to: 'wgs84'
}

/**
 * 深色样式
 */
const Dark_Style = {
    textColor: '#F8F8FF',
    haloColor: '#8B8B8B',
    haloWidth: 0.1,
    haloBlur: 0,

    boundaryColor: '#92FBE2', // 区域边界颜色  FFD188
}

/**
 * 浅色地图样式
 */
const Light_Style = {
    textColor: '#191970',
    textHaloWidth: 0.25,
    boundary_lineColor: '#4169E1',
}

/**
 * Token工具
 */
const TokenUtils = {
    /*mapbox_token*/
    MapboxGL_AccessToken: 'pk.eyJ1IjoibWJuZ2hkIiwiYSI6ImNtNjV3YnVmNTFzem4ya3NveTQ0c3p2ZHEifQ.ILnudtLw6aF2YujqXBQpSQ',
    /*cesium_token*/
    Cesium_AccessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2OTgxNTY1Ni05ZWQzLTQ5OWMtODVlMS1kZTQyNzE5ODkyMzYiLCJpZCI6MTUzNDgsInNjb3BlcyI6WyJhc2wiLCJhc3IiLCJhc3ciLCJnYyJdLCJpYXQiOjE1Njc2NTMzMzZ9.lgaMvwkiWOimFhfJ4dgfNmKZDfjqIPaAfg0ycjwFTfc',
    /*天地图企业token*/
    TDT_token: '7ecf165a6717ea33c926889518f26fa4'
}

let pendingRequests = new Set();
const throttleDelay = 300; // 300ms 内相同瓦片不重复请求

class MapboxNative {
    constructor() {
        this.workspace = mapConfig.workspace;
        this.mapType = "vector";
        this.vectorSignalStr = ['vec', 'cva'];
        this.imageSignalStr = ['img', 'cia'];
        this.map_srid = mapConfig.map_srid;
        this.business_srid = mapConfig.business_srid;
        this.mbMap = null;
        this.styleUrl = mapConfig.mapUrl + '/mapbox-gl/style';
        this.opts = {};

        // 图标资源
        this.point_icon = require('../../baseSetting/images/map/point.png');
        this.img_todo = require('../../baseSetting/images/map/todo.png');
        this.img_done = require('../../baseSetting/images/map/done.png');
        this.img_invalid = require('../../baseSetting/images/map/invalid.png');
        this.img_error = require('../../baseSetting/images/map/error.png');

        // 颜色配置
        this.actual_color = '#7ed321';
        this.plan_color_valid = '#3a6bdb';
        this.plan_color_invalid = '#9b9b9b';
    }

    /**
     * 创建地图实例
     * theme = 'dark'时 将使用离线暗色底图瓦片,将mapConfig中的isOnline设置为false,此时默认使用文件服务器上的暗色瓦片资源
     * theme = 'light'时 将使用在线亮色底图瓦片,将mapConfig中的isOnline设置为true,此时默认使用天地图资源
     * theme = 'light'时 将使用在线亮色底图瓦片,将mapConfig中的isOnline设置为false,此时默认使用文件服务器上的亮色瓦片资源
     * @param opts
     * @param callback
     */
    create (opts, callback) {
        this.opts = opts
        if (mapConfig.noMap) {
            this.$message.info("未配置地图")
            alert("未配置地图")
            return
        } else {
            if (typeof mapboxgl == 'undefined') {
                // 使用 Promise 确保资源加载完成后再执行后续逻辑
                this.loadMapboxResources().then(() => {
                    this.initMap(opts, callback);
                }).catch((error) => {
                    console.error("地图资源加载失败:", error);
                    callback && callback();
                });
            } else {
                this.initMap(opts, callback);
            }
        }
    }

    /**
     * 添加图标资源
     * @param map
     */
    addImageSource (map) {
        // 添加图标到地图
        if (!map.hasImage('img_done')) {
            map.loadImage(this.img_done, (error, image) => {
                if (error) throw error;
                map.addImage('img_done', image);
            });
        }

        if (!map.hasImage('img_error')) {
            map.loadImage(this.img_error, (error, image) => {
                if (error) throw error;
                map.addImage('img_error', image);
            });
        }

        if (!map.hasImage('img_invalid')) {
            map.loadImage(this.img_invalid, (error, image) => {
                if (error) throw error;
                map.addImage('img_invalid', image);
            });
        }

        if (!map.hasImage('img_todo')) {
            map.loadImage(this.img_todo, (error, image) => {
                if (error) throw error;
                map.addImage('img_todo', image);
            });
        }
    }

    /**
     * 加载必要的资源(地图框架以及通用资源)
     * @returns {Promise<unknown>}
     */
    loadMapboxResources () {
        return new Promise((resolve, reject) => {
            const script = document.createElement("script");
            script.src = mapConfig.mapUrl + "/mapbox-gl/mapbox-gl.js";

            const link = document.createElement("link");
            link.href = mapConfig.mapUrl + "/mapbox-gl/mapbox-gl.css";
            link.rel = "stylesheet";

            // 风格样式文件
            const linkSearch = document.createElement("link");
            linkSearch.href = mapConfig.mapUrl + "/mapbox-gl/gis-" + this.opts.theme + ".css";
            linkSearch.rel = "stylesheet";

            let scriptLoaded = false;
            let linkLoaded = false;
            let linkSearchLoaded = false;

            const checkComplete = () => {
                if (scriptLoaded && linkLoaded && linkSearchLoaded) {
                    resolve();
                }
            };

            script.onload = () => {
                scriptLoaded = true;
                checkComplete();
            };

            link.onload = () => {
                linkLoaded = true;
                checkComplete();
            };

            linkSearch.onload = () => {
                linkSearchLoaded = true;
                checkComplete();
            };

            script.onerror = () => reject(new Error("Mapbox GL JS 加载失败"));
            link.onerror = () => reject(new Error("Mapbox GL CSS 加载失败"));
            linkSearch.onerror = () => reject(new Error("gis公共样式 加载失败"));

            document.body.appendChild(script);
            document.body.appendChild(link);
            document.body.appendChild(linkSearch);
        });
    }

    /**
     * 初始化地图
     * @param opts
     * @param callback
     */
    initMap (opts, callback) {
        // 原有的地图初始化逻辑...
        // 自定义样式
        let baseSources = {}, baseLayers = [];
        const customStyle = opts.theme === "dark" ? Dark_Style : Light_Style;
        if (mapConfig.isOnline) {
            const basemapType = mapConfig.map_srid === 'EPSG:3857' ? 'w' : 'c';
            switch (this.mapType) {
                case "vector":
                    this.vectorSignalStr.forEach(signal => {
                        baseSources['tdt_' + signal + '_tiles'] = {
                            type: 'raster',
                            tiles: [
                                'https://t0.tianditu.gov.cn/' + signal + '_' + basemapType + '/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=' + signal + '&STYLE=default&TILEMATRIXSET=' + basemapType + '&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TokenUtils.TDT_token,
                            ],
                            scheme: 'xyz', // 显式指定
                            minzoom: 0,
                            maxzoom: mapConfig.maxOnlineZoom,
                            tileSize: 256
                        }
                    })
                    break
                case "raster":
                    this.imageSignalStr.forEach(signal => {
                        baseSources['tdt_' + signal + '_tiles'] = {
                            type: 'raster',
                            tiles: [
                                'https://t0.tianditu.gov.cn/' + signal + '_' + basemapType + '/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=' + signal + '&STYLE=default&TILEMATRIXSET=' + basemapType + '&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TokenUtils.TDT_token,
                            ],
                            scheme: 'xyz', // 显式指定
                            minzoom: 0,
                            maxzoom: mapConfig.maxOnlineZoom,
                            tileSize: 256
                        }
                    })
                    break
                default:
                    break
            }
            for (let source in baseSources) {
                baseLayers.push({
                    id: source,
                    type: 'raster',
                    source: source,
                    minzoom: 0,
                    maxzoom: mapConfig.maxOnlineZoom,
                })
            }
        } else {
            // 基础图层列表
            baseSources = opts.theme === "dark" ? this.getGeoserverSources(Dark_Sources) : { ...this.formatBaseSource(base_sources), ...this.getGeoserverSources(Light_Sources) };
            baseLayers = opts.theme === "dark" ? Dark_Layers : Light_Layers;
        }

        // 业务图层列表
        const businessLayers = opts.theme === "dark" ? business_layers : business_layers;

        let businessSources = this.getGeoserverSources(business_sources)

        const mapId = opts.mapId;

        mapboxgl.accessToken = TokenUtils.MapboxGL_AccessToken;

        console.log('baseSources, baseLayers', baseSources, baseLayers);

        // 优化并发
        mapboxgl.config.MAX_PARALLEL_IMAGE_REQUESTS = 256;


        this.mbMap = new mapboxgl.Map({
            container: mapId,
            minZoom: mapConfig.minZoom,
            maxZoom: mapConfig.isOnline ? mapConfig.maxOnlineZoom : mapConfig.maxZoom,
            zoom: mapConfig.zoom,
            center: mapConfig.center,
            maxBounds: [
                [mapConfig.mapExtent[0], mapConfig.mapExtent[1]],   // 西南角坐标 [minX, minY]
                [mapConfig.mapExtent[2], mapConfig.mapExtent[3]]   // 东北角坐标 [maxX, maxY]
            ],
            pitch: mapConfig.pitch, // 地图初始化时的倾角，按偏离屏幕水平面的度数计量（0-60）
            bearing: mapConfig.bearing, // 地图初始化时的方位角（旋转角度），以正北方的逆时针转动度数计量
            preserveDrawingBuffer: true, // 用于导出图片
            constrainMode: 'width-and-height', // 限制地图在容器范围内
            renderWorldCopies: false, // 避免重复渲染世界副本
            dragRotate: false,        // 禁用拖拽旋转
            touchZoom:  true,        // 禁用触摸缩进
            touchRotate: false,      // 禁用触摸旋转
            style: {
                version: 8,
                name: "mb_map_style",
                sprite: this.styleUrl + "/sprite/" + opts.theme + "/sprite",
                glyphs: this.styleUrl + "/fonts/{fontstack}/{range}.pbf",
                transition: {
                    duration: 300,
                    delay: 0,
                },
                sources: {
                    ...baseSources
                },
                layers: baseLayers
            },
            // 添加以下配置来隐藏控件
            attributionControl: false // 这会同时隐藏 logo 和 attribution
        });

        const map = this.mbMap

        this.setStyle(map);

        this.addImageSource(this.mbMap)

        this.mbMap._customStyle = customStyle

        this.mbMap.on('load', () => {
            // 在地图加载完成后调用
            // this._drawGridWithCenterLabels(map) // 测试用
            // this.resetCenterAndZoom(map)

            // 默认获取点击坐标位置
            this.mbMap.on('click', (pos) => {
                console.log(`点击位置 - 经度: ${pos.lngLat.lng}, 纬度: ${pos.lngLat.lat}`);
                // 变量记录
                window.currentLocation = [pos.lngLat.lng, pos.lngLat.lat]
                this.getFeature(pos)
            })

            // @csk 离线瓦片加载最大层级出现空白情况的处理
            this.mbMap.on('zoom', () => {
                const currentZoom = this.mbMap.getZoom();
                if (currentZoom > mapConfig.maxZoom) {
                    this.mbMap.setZoom(mapConfig.maxZoom);
                }
            });
            // 或者更精确地处理
            this.mbMap.on('zoomend', () => {
                const currentZoom = this.mbMap.getZoom();
                if (currentZoom >= mapConfig.maxZoom) {
                    this.mbMap.flyTo({
                        zoom: mapConfig.maxZoom,
                        duration: 0 // 瞬间跳转
                    });
                }
            });

            this.hideLogo()


            this.mbMap.resize() //确保各类页面map均尺寸正确
            // Mapbox GL JS不需要动态加载脚本
            callback && callback(this.mbMap);
        });

        //@csk 瓦片请求优化（节流）
        this.mbMap.on('tile_request', (e) => {
            const url = e.url;
            if (pendingRequests.has(url)) {
                e.preventDefault(); // 阻止重复请求
                return;
            }
            pendingRequests.add(url);
            setTimeout(() => pendingRequests.delete(url), throttleDelay);
        });
    }

    /**
     * 获取要素(点选)
     * @param e
     */
    getFeature (e) {
        // 获取点击位置的要素
        const features = map.queryRenderedFeatures(e.point);

        if (features.length > 0) {
            const feature = features[0];
            console.log('点击的要素:', feature.properties);
        }
    }

    /**
     * 隐藏MapBoxgl logo
     */
    hideLogo () {
        console.log('logo is hidden')
        let controls = map._controls;
        controls.forEach(control => {
            // 去除logo控件
            if ('_updateLogo' in control) {
                map.removeControl(control)
            }

            // 去除attribute控件
            if ('_attribHTML' in control) {
                map.removeControl(control)
            }
        })
    }

    /**
     * 格式化基础图层源
     * @param sources
     * @returns {*}
     */
    formatBaseSource (sources) {
        for (let lyrName in sources) {
            // 瓦片服务地址为空时，使用默认地址，否则使用geoserver地址
            if (!sources[lyrName].hasOwnProperty('tiles')) {
                let tiles = this.joinTmsUrl(lyrName);
                sources[lyrName].tiles = [tiles];
            }
        }
        return sources
    }

    /**
     * 切换底图
     * @param {String} type -目标底图类型
     */
    changeMap (type) {
        if (!this.mbMap || type === this.mapType) return;

        let changedLayers = null;
        switch (type) {
            case 'vector':
                changedLayers = Vector_Layers;
                break;
            case 'image':
                changedLayers = Image_Layers;
                break;
            default:
                return;
        }

        // 设置是否显示
        changedLayers.forEach(layer => {
            if (this.mbMap.getLayer(layer.id)) {
                this.mbMap.setLayoutProperty(layer.id, 'visibility', layer.visibility);
            }
        });

        this.mapType = type;
    }

    /**
     * 重置地图中心点和缩放级别
     * @param map
     */
    resetCenterAndZoom (map) {
        if (!map) return;
        map.jumpTo({ center: mapConfig.center, zoom: mapConfig.zoom });
        console.log('地图已重置到默认中心点和缩放级别');
    }

    /**
     * 拼接WMTS服务地址
     * @param layerName -图层名称
     */
    joinWmtsUrl (layerName) {
        return (
                mapConfig.mapUrl +
                "/geoserver/gwc/service/wmts?request=GetTile" +
                "&service=WMTS" +
                "&version=1.0.0" +
                "&layer=" +
                this.workspace +
                ":" +
                layerName +
                "&style=" +
                "&tilematrixset=" +
                this.map_srid +
                "&tilematrix=" +
                this.map_srid +
                ":{z}" +
                "&format=image/png" +
                "&tilecol={x}" +
                "&tilerow={y}"
        );
    }

    /**
     * 拼接TMS服务地址
     * @param layerName -图层名称
     */
    joinTmsUrl (layerName) {
        return (
                mapConfig.mapUrl +
                "/geoserver/gwc/service/tms/1.0.0/" +
                this.workspace +
                ":" +
                layerName +
                "@" +
                this.map_srid +
                "@pbf/{z}/{x}/{y}.pbf"
        );
    }

    /**
     * 获取TMS服务地址
     * @param z
     * @param x
     * @param y
     * @returns {string}
     */
    getTmsUrl (z, x, y) {
        const ymax = Math.pow(2, z) - 1;
        const y_tms = ymax - y;
        return mapConfig.mapUrl + `/gis-data/shenzhen/${z}/${x}/${y_tms}.png`;
    }

    /**
     * 拼接WFS服务地址
     * @param {String} layerName -图层名称
     * @param {String} category -类别(pipeline、manhole等)
     */
    joinWfsUrl (layerName, category = null) {
        let url = mapConfig.mapUrl +
                "/geoserver/" +
                this.workspace +
                "/ows?request=GetFeature" +
                "&service=WFS" +
                "&version=1.1.0" +
                "&typeName=" +
                this.workspace +
                ":" +
                layerName +
                "&outputFormat=application/json" +
                "&srsName=" +
                this.map_srid;

        if (category) {
            // 全局图层管理器入口
            const layers = LayerConfig.Layers.filter((lc) => {
                return lc.parent === category;
            });
            if (layers.length > 0 &&
                    layers[0].fields && layers[0].fields.length > 0) {
                url += "&propertyName=geom,";
                url += layers[0].fields;
            }
        }

        return url;
    }

    /**
     * 获取WFS服务查询根URL
     *
     * @returns {String}
     */
    getWfsQueryUrl () {
        return (
                mapConfig.mapUrl + "/geoserver/" + this.workspace +
                "/ows?service=WFS&version=1.0.0" +
                "&request=GetFeature" +
                "&outputFormat=application/json" +
                "&maxFeatures=2500" +
                "&srsName=" + this.map_srid +
                "&typeName="
        );
    }

    /**
     * 获取数据源
     * @param {Array} configs -数据源配置列表
     *
     * @returns {Object} 数据源对象
     */
    getGeoserverSources (configs) {
        const dataSources = {};
        configs.filter(src => !src.category).forEach((ds) => {
            // 获取数据源对象
            const sourceObj = this.getGeoserverSource(ds);
            if (sourceObj) {
                dataSources[ds.id] = sourceObj;
            }
        });

        return dataSources;
    }

    /**
     * 获取数据源对象
     * @param {Object} options -数据源配置
     *
     * @returns {Object}
     */
    getGeoserverSource (options) {
        switch (options.type) {
            case 'raster': { // GeoServer-栅格瓦片服务
                return {
                    type: options.type,
                    scheme: options.scheme || 'xyz',
                    tiles: [
                        this.joinWmtsUrl(options.geoLayer, options.workspace)
                    ],
                    minzoom: options.minZoom || 0,
                    maxzoom: options.maxZoom || 22
                };
            }
            case 'vector': { // GeoServer-矢量瓦片服务
                return {
                    type: options.type,
                    scheme: options.scheme || 'tms',
                    tiles: [
                        this.joinTmsUrl(options.geoLayer, options.workspace)
                    ],
                    minzoom: options.minZoom || 0,
                    maxzoom: options.maxZoom || 22
                };
            }
            case 'geojson': { // GeoServer-WFS服务
                return {
                    type: options.type,
                    data: this.joinWfsUrl(options.geoLayer, options.srid, options.fields)
                };
            }
            default:
                return null;
        }
    }

    /**
     * 添加自定义瓦片图层
     */
    addTiles (map) {
        if (!map) return;

        // 添加自定义瓦片图层
        map.addSource('custom-tiles', {
            type: 'raster',
            tiles: ['/images/tiles/{z}/{x}/{y}.png'],
            tileSize: 256
        });

        map.addLayer({
            id: 'custom-tiles-layer',
            type: 'raster',
            source: 'custom-tiles',
            minzoom: 0,
            maxzoom: 22
        });
    }

    /**
     * 定位到当前位置
     */
    placePoint (map, location, callback) {
        if (!map) return;
        if (Array.isArray(location) && location.length === 2) {
            map.setCenter(location)
            map.setZoom(mapConfig.zoom);
        } else {
            navigator.geolocation.getCurrentPosition(
                    (position) => {
                        console.log('navigator.geolocation', position);
                        const point = {
                            lng: position.coords.longitude,
                            lat: position.coords.latitude
                        };

                        map.setCenter([point.lng, point.lat]);
                        map.setZoom(mapConfig.maxZoom);
                        callback && callback(point);
                    },
                    (error) => {
                        // 默认定位到地图中心点
                        const point = { lng: mapConfig.center[0], lat: mapConfig.center[1] };
                        map.setCenter([point.lng, point.lat]);
                        map.setZoom(mapConfig.maxZoom);
                        callback && callback(point);
                    },
                    { enableHighAccuracy: true }
            );
        }
    }

    /**
     * @param data
     */
    addMarker (data) {
        console.log('addMarker>>>>>>')
        // 清除之前的标记图层和数据源
        if (this.mbMap.getLayer('marker-point')) {
            this.mbMap.removeLayer('marker-point');
        }
        if (this.mbMap.getSource('marker-point')) {
            this.mbMap.removeSource('marker-point');
        }

        if (data.longitude && data.latitude) {
            // 确保图标已加载到地图中
            if (!this.mbMap.hasImage('add_marker_icon')) {
                this.mbMap.loadImage(this.point_icon, (error, image) => {
                    if (error) throw error;
                    this.mbMap.addImage('add_marker_icon', image);
                });
            }

            // 创建GeoJSON数据源
            const geojson = {
                type: 'FeatureCollection',
                features: [{
                    type: 'Feature',
                    geometry: {
                        type: 'Point',
                        coordinates: [data.longitude, data.latitude]
                    },
                    properties: {}
                }]
            };

            // 添加数据源
            this.mbMap.addSource('marker-point', {
                type: 'geojson',
                data: geojson
            });

            // 添加图层显示标记点（使用自定义图标）
            this.mbMap.addLayer({
                id: 'marker-point',
                type: 'symbol',
                source: 'marker-point',
                layout: {
                    'icon-image': 'add_marker_icon',
                    'icon-size': 1,
                    'icon-offset': [4, -19]
                }
            });

            // 设置地图中心点和缩放级别
            this.mbMap.setCenter([data.longitude, data.latitude]);
            this.mbMap.setZoom(mapConfig.maxZoom || 18);
        }
    }

    /**
     * 设置地图样式
     */
    setStyle (map) {
        if (!map) return;

        // 独立设置需要的mapbox内置样式
        // 请使用我提供给你的base64 png图片 并进行addImage操作 iVBORw0KGgoAAAANSUhEUgAAAAsAAAArCAYAAABm8CLRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqkld9LAlEUxr93Z3fHXV1bE1JLMoheIh/6B/oHIiilICjohR76A4KgHnroTwh6CIKgICIzKCvNMnVdXd3ZnbnndIcZZ3bWEPoNDnfuOed855tzzz1XGGNgGIbxf8DpdF5omoZer/eXpmmYTCaIRCJot9vwer3wer0wmUwAgFarhXa7jXa7jVarhXa7jU6ng263i16vh36/DwAYDAaIRCKIRCJE0zQMDAzAarWCZVlgjIFSCkopKKXgeR6CICAIAjiOA8dxIIQAQghIkoQkSSBJEkRRhCiKEEURPM+DYRgwDAOGYUBRFCiKAkVRoKoqVFUFpRSapkHzPGiapnnDMAzDMAzDMIzf8M8BXq8XPp8PPp8Poij+9Xg8hkajgXq9jkajgXq9jnq9jmazCUIIGGOglILneQiCAEEQIAgCOI4Dx3EQBAEcxyEQCECWZUiShEAgALvdDovFAovFApvNBovFAkmSIEmSJEnSNVmW/1JV9Zym6XOaptc0TT/QNP1A0/QDTdMPNE0/0DR9T9P0PU3TdzRN39I0fUPT9DVN01c0TV/SNH1B0/Q5TdOnNE2f0DR9TNP0EU3ThzRNH9A0vU/T9B5N07s0Te/SNL1D0/Q2TdNbNE1v0jS9QdP0Ok3TazRNr9I0vULT9DJN00s0TS/SNL1A0/Q8TdNzNE3P0jQ9Q9P0NE3TUzRN/6Rp+jhN00c0TR/SNH1A0/Q+TdN7NE3v0jS9Q9P0Nk3TWzRNb9I0vUHT9DpN02s0Ta/SNL1C0/QyTdNLNE0v0jS9QNP0PE3TczRNz9I0PUMmk0kkEgnE43HE43HE43HEYjFomgZKKSilIIQAAARBAM/zEAQBgiCA53nwPA+e58HzPHiehyAI4DgOHMeB53lwHAeO48BxHHiehyAI4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOPM+D53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB/wD/BGAAuJZK3XZCtKsAAAAASUVORK5CYII=
        // 添加基于base64的自定义图片资源
        if (!map.hasImage('custom_circle_icon')) {
            const img = new Image();
            img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAArCAYAAABm8CLRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqkld9LAlEUxr93Z3fHXV1bE1JLMoheIh/6B/oHIiilICjohR76A4KgHnroTwh6CIKgICIzKCvNMnVdXd3ZnbnndIcZZ3bWEPoNDnfuOed855tzzz1XGGNgGIbxf8DpdF5omoZer/eXpmmYTCaIRCLot9vwer3wer0wmUwAgFarhXa7jXa7jVarhXa7jU6ng263i16vh36/DwAYDAaIRCKIRCJE0zQMDAzAarWCZVlgjIFSCkopKKXgeR6CICAIAjiOA8dxIIQAQghIkoQkSSBJEkRRhCiKEEURPM+DYRgwDAOGYUBRFCiKAkVRoKoqVFUFpRSapkHzPGiapnnDMAzDMIzDMIzf8M8BXq8PPp8PPp8Poij+9Xg8hkajgXq9jkajgXq9jnq9jmazCUIIGGOglILneQiCAEEQIAgCOI4Dx3EQBAEcxyEQCECWZUiShEAgALvdDovFAovFApvNBovFAkmSIEmSJEnSNVmW/1JV9Zym6XOaptc0TT/QNP1A0/QDTdMPNE0/0DR9T9P0PU3TdzRN39I0fUPT9DVN01c0TV/SNH1B0/Q5TdOnNE2f0DR9TNP0EU3ThzRNH9A0vU/T9B5N07s0Te/SNL1D0/Q2TdNbNE1v0jS9QdP0Ok3TazRNr9I0vULT9DJN00s0TS/SNL1A0/Q8TdNzNE3P0jQ9Q9P0NE3TUzRN/6Rp+jhN00c0TR/SNH1A0/Q+TdN7NE3v0jS9Q9P0Nk3TWzRNb9I0vUHT9DpN02s0Ta/SNL1C0/QyTdNLNE0v0jS9QNP0PE3TczRNz9I0PUMmk0kkEgnE43HE43HEYjFomgZKKSilIIQAAARBAM/zEAQBgiCA53nwPA+e58HzPHiehyAI4DgOHMeB53lwHAeO48BxHHiehyAI4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOPM+D53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB53nwPA9BECAIAjiOA8dx4DgOHMeB/wD/BGAAuJZK3XZCtKsAAAAASUVORK5CYII=';
            img.onload = () => {
                map.addImage('custom_circle_icon', img);
            };
        }

        // Mapbox GL JS使用不同的样式设置方式
        // 这里可以设置预定义样式或自定义样式
        // map.setStyle('mapbox://styles/mapbox/streets-v11');
    }

    /**
     * 设置地图缩放级别和中心点
     */
    setZoom (map, points, zoomLevel = null) {
        if (!map || !points || points.length === 0) return;

        let coordinates;
        if (typeof points[0] === 'number' && points.length % 2 === 0) {
            // 处理扁平数组格式
            coordinates = [];
            for (let i = 0; i < points.length; i += 2) {
                coordinates.push([points[i], points[i + 1]]);
            }
        } else {
            // 处理对象数组格式
            coordinates = points.map(p => [p.longitude, p.latitude]);
        }

        // 计算所有坐标的边界框
        const bounds = coordinates.reduce(
                (bbox, coord) => {
                    return [
                        Math.min(bbox[0], coord[0]), // 最小经度
                        Math.min(bbox[1], coord[1]), // 最小纬度
                        Math.max(bbox[2], coord[0]), // 最大经度
                        Math.max(bbox[3], coord[1])  // 最大纬度
                    ];
                },
                [Infinity, Infinity, -Infinity, -Infinity] // 初始边界
        );

        if (zoomLevel) {
            const center = [
                (bounds[0] + bounds[2]) / 2,
                (bounds[1] + bounds[3]) / 2
            ];
            map.setCenter(center);
            map.setZoom(zoomLevel);
        } else {
            map.fitBounds(
                    [[bounds[0], bounds[1]], [bounds[2], bounds[3]]],
                    {
                        padding: 80,
                        maxZoom: 16,
                        duration: 800
                    }
            );
        }
    }

    /**
     * 绘制巡检任务
     */
    drawPatrolTask (map, data) {
        if (!map || !data) return;

        const points = data.patrolPointDetailDTOs || [];
        const lines = data.patrolTaskPlanPaths || [];

        if (!points.length || !lines.length) return;

        this.setZoom(map, points);

        // 清除之前的图层
        if (map.getLayer('patrol-points')) map.removeLayer('patrol-points');
        if (map.getSource('patrol-points')) map.removeSource('patrol-points');
        if (map.getLayer('patrol-lines')) map.removeLayer('patrol-lines');
        if (map.getSource('patrol-lines')) map.removeSource('patrol-lines');

        // 添加点数据
        const pointFeatures = points.map(po => ({
            type: 'Feature',
            geometry: {
                type: 'Point',
                coordinates: [po.longitude, po.latitude]
            },
            properties: {
                ...po
            }
        }));

        map.addSource('patrol-points', {
            type: 'geojson',
            data: {
                type: 'FeatureCollection',
                features: pointFeatures
            }
        });

        // 根据状态设置不同图标
        map.addLayer({
            id: 'patrol-points',
            type: 'circle',
            source: 'patrol-points',
            paint: {
                'circle-radius': 6,
                'circle-color': [
                    'match',
                    ['get', 'status'],
                    '正常', '#7ed321',
                    '异常', '#ff0000',
                    '未检', '#9b9b9b',
                    '#3a6bdb' // 默认颜色
                ],
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff'
            }
        });

        // 添加点标签
        map.addLayer({
            id: 'patrol-point-labels',
            type: 'symbol',
            source: 'patrol-points',
            layout: {
                'text-field': ['get', 'patrolPoint'],
                'text-offset': [0, 1.5],
                'text-anchor': 'top'
            },
            paint: {
                'text-color': '#0093ff'
            }
        });

        // 添加线数据
        if (lines.length >= 2) {
            const lineFeatures = [];
            for (let i = 0; i < lines.length - 1; i++) {
                lineFeatures.push({
                    type: 'Feature',
                    geometry: {
                        type: 'LineString',
                        coordinates: [
                            [lines[i].longitude, lines[i].latitude],
                            [lines[i + 1].longitude, lines[i + 1].latitude]
                        ]
                    },
                    properties: {
                        validate: lines[i].validate
                    }
                });
            }

            map.addSource('patrol-lines', {
                type: 'geojson',
                data: {
                    type: 'FeatureCollection',
                    features: lineFeatures
                }
            });

            map.addLayer({
                id: 'patrol-lines',
                type: 'line',
                source: 'patrol-lines',
                paint: {
                    'line-color': [
                        'match',
                        ['get', 'validate'],
                        'valid', plan_color_valid,
                        plan_color_invalid
                    ],
                    'line-width': 4
                }
            });
        }
    }

    /**
     * 绘制巡检路径
     */
    drawPatrol (map, data, pointField) {
        if (!map || !data) return;
        const taskUniqueId = data.id || data.patrolTaskId;
        if (!taskUniqueId) return;

        const points = data.patrolTaskPointTrackDTOs || [];
        const lines = data.patrolTaskPlanPaths || [];
        if (!points.length || !lines.length) return;

        this.setZoom(map, points);

        // 定义动态唯一ID
        const pointSourceId = `patrol-track-points-${taskUniqueId}`;
        const pointIconLayerId = `patrol-track-points-icons-${taskUniqueId}`;
        const pointLabelLayerId = `patrol-track-point-labels-${taskUniqueId}`;
        const lineSourceId = `patrol-track-lines-${taskUniqueId}`;
        const lineLayerId = `patrol-track-lines-${taskUniqueId}`;

        // 清除旧图层/数据源（使用动态ID）
        if (map.getLayer(pointIconLayerId)) map.removeLayer(pointIconLayerId);
        if (map.getLayer(pointLabelLayerId)) map.removeLayer(pointLabelLayerId);
        if (map.getSource(pointSourceId)) map.removeSource(pointSourceId);
        if (map.getLayer(lineLayerId)) map.removeLayer(lineLayerId);
        if (map.getSource(lineSourceId)) map.removeSource(lineSourceId);

        // 添加点数据
        const pointFeatures = points.map(po => ({
            type: 'Feature',
            geometry: {
                type: 'Point',
                coordinates: [po.longitude, po.latitude]
            },
            properties: {
                ...po
            }
        }));

        // 在 addSource 中添加图标属性
        map.addSource(pointSourceId, {
            type: 'geojson',
            data: {
                type: 'FeatureCollection',
                features: pointFeatures.map(feature => {
                    let icon;
                    const status = feature.properties.status;
                    switch (status) {
                        case '正常': icon = 'img_done'; break;
                        case '异常': icon = 'img_error'; break;
                        case '未检': icon = 'img_invalid'; break;
                        default: icon = 'img_todo'; break;
                    }
                    return {
                        ...feature,
                        properties: { ...feature.properties, icon: icon }
                    };
                })
            }
        });

        // 在图层中使用图标
        map.addLayer({
            id: pointIconLayerId,
            type: 'symbol',
            source: pointSourceId,
            layout: {
                'icon-image': ['get', 'icon'],
                'icon-size': 1,
                'icon-anchor': 'bottom'
            }
        });

        // 添加点标签
        map.addLayer({
            id: pointLabelLayerId,
            type: 'symbol',
            source: pointSourceId,
            layout: {
                'text-field': ['get', 'patrolPointName'],
                'text-offset': [0, 1.5],
                'text-anchor': 'top'
            },
            paint: { 'text-color': '#0093ff' }
        });

        // 添加线数据,绑定任务信息到 properties
        if (lines.length >= 2) {
            const lineFeatures = [];
            for (let i = 0; i < lines.length - 1; i++) {
                lineFeatures.push({
                    type: 'Feature',
                    geometry: {
                        type: 'LineString',
                        coordinates: [
                            [lines[i].longitude, lines[i].latitude],
                            [lines[i + 1].longitude, lines[i + 1].latitude]
                        ]
                    },
                    properties: {
                        validate: lines[i].validate,
                        taskId: taskUniqueId,
                        taskInfo: {
                            name: data.name,
                            executeStatus: data.executeStatus,
                            startTime: data.startTime,
                            endTime: data.endTime,
                            faultCount: data.faultCount,
                            patrolPointCount: data.patrolPointCount,
                            inspectedCount: data.inspectedCount,
                            planPathLength: data.planPathLength,
                            validPathLength: data.validPathLength
                        }
                    }
                });
            }

            map.addSource(lineSourceId, {
                type: 'geojson',
                data: { type: 'FeatureCollection', features: lineFeatures }
            });

            map.addLayer({
                id: lineLayerId,
                type: 'line',
                source: lineSourceId,
                paint: {
                    'line-color': ['match', ['get', 'validate'], 'valid', plan_color_valid, plan_color_invalid],
                    'line-width': 4,
                    'line-dasharray': [2, 2]
                },
                interactive: true // 开启线图层点击交互
            });
        }

        // console.log('当前地图图层ID列表:', map.getStyle().layers.map(layer => layer.id));
    }

    /**
     * 添加搜索功能
     * @param {string} containerId - 搜索输入框的容器ID
     * @param {Array} bounds - 搜索边界范围
     * @param {Function} callback - 回调函数
     */
    addSearch (containerId, bounds = [], callback) {
        // 检查容器ID是否存在
        if (!containerId) return;

        // 通过容器ID获取输入框元素
        const inputElement = document.getElementById(containerId);
        inputElement.setAttribute('placeholder', '请输入搜索内容并通过↩︎进行查询')
        if (!inputElement) {
            console.error(`未找到ID为 ${containerId} 的输入框元素`);
            return;
        }

        // 创建搜索结果容器并插入到输入框下方
        let resultListContainer = document.getElementById(`${containerId}-results`);
        if (!resultListContainer) {
            resultListContainer = document.createElement('div');
            resultListContainer.id = `${containerId}-results`;
            resultListContainer.className = 'search-results-container';
            inputElement.parentNode.insertBefore(resultListContainer, inputElement.nextSibling);
        }

        // 默认隐藏搜索结果容器
        resultListContainer.style.display = 'none';

        // 监听输入事件，当输入为空时清空并隐藏结果列表
        inputElement.addEventListener('input', (event) => {
            const keyword = event.target.value.trim();
            if (!keyword) {
                // 清空并隐藏搜索结果列表
                this.clearSearchResults(containerId);
            }
        });

        inputElement.addEventListener('keydown', (event) => {
            if (event.key === 'Enter') {
                event.preventDefault();
                const keyword = inputElement.value.trim();
                if (keyword) {
                    this.executeSearch(containerId, bounds, (poiList) => {
                        // 展示搜索结果列表
                        this.showSearchResults(containerId, poiList);
                        callback && callback(poiList);
                    });
                } else {
                    // 如果输入为空，清空并隐藏结果列表
                    this.clearSearchResults(containerId);
                }
            }
        });

        // 添加输入框失去焦点时隐藏结果列表的事件
        inputElement.addEventListener('blur', () => {
            // 延迟隐藏，确保点击列表项时不会立即隐藏
            setTimeout(() => {
                if (resultListContainer) {
                    resultListContainer.style.display = 'none';
                }
            }, 200);
        });

        // 添加输入框获得焦点时显示结果列表的事件（如果有结果）
        inputElement.addEventListener('focus', () => {
            if (resultListContainer && resultListContainer.children.length > 0) {
                resultListContainer.style.display = 'block';
            }
        });
    }

    /**
     * 清空并隐藏搜索结果列表
     * @param {string} containerId - 搜索输入框的容器ID
     */
    clearSearchResults (containerId) {
        const resultListContainer = document.getElementById(`${containerId}-results`);
        if (resultListContainer) {
            resultListContainer.innerHTML = '';
            resultListContainer.style.display = 'none';
        }

        // 同时清除地图上的POI结果
        this.clearPOIResults();
    }

    /**
     * 展示搜索结果列表
     * @param {string} containerId - 搜索输入框的容器ID
     * @param {Array} poiList - POI结果列表
     */
    showSearchResults (containerId, poiList) {
        const resultListContainer = document.getElementById(`${containerId}-results`);
        if (!resultListContainer) return;

        // 清空容器内容
        resultListContainer.innerHTML = '';

        if (!poiList || poiList.length === 0) {
            resultListContainer.innerHTML = '<div class="no-results">未找到相关结果</div>';
            resultListContainer.style.display = 'block';
            return;
        }

        // 创建结果列表
        const resultList = document.createElement('ul');
        resultList.className = 'search-result-list';

        // 为每个POI创建列表项
        poiList.forEach((poi, index) => {
            const listItem = document.createElement('li');
            listItem.className = 'search-result-item';
            listItem.dataset.index = index;

            // 设置列表项内容
            listItem.innerHTML = `
            <div class="result-item-header">
                <span class="result-item-name">${poi.name || '未知名称'}</span>
                ${poi.type ? `<span class="result-item-type">${poi.type}</span>` : ''}
            </div>
            ${poi.address ? `<div class="result-item-address">${poi.address}</div>` : ''}
            ${poi.tel ? `<div class="result-item-tel">电话: ${poi.tel}</div>` : ''}
        `;

            // 绑定点击事件，实现定位功能
            listItem.addEventListener('mousedown', (e) => {
                // 使用mousedown而不是click，避免blur事件先触发
                e.preventDefault();
                this.focusOnPOI(poi);
            });

            resultList.appendChild(listItem);
        });

        resultListContainer.appendChild(resultList);
        resultListContainer.style.display = 'block';
    }

    /**
     * 定位到指定POI
     * @param {Object} poi - POI对象
     */
    focusOnPOI (poi) {
        if (!this.mbMap || !poi || !poi.longitude || !poi.latitude) return;

        // 移动地图到POI位置
        this.mbMap.flyTo({
            center: [poi.longitude, poi.latitude],
            zoom: 16,
            essential: true // 动画不受 prefers-reduced-motion 影响
        });

        // 高亮显示该POI（如果地图上已有POI结果图层）
        if (this.mbMap.getSource('poi-results')) {
            // 创建临时标记
            const popup = new mapboxgl.Popup({
                closeButton: false,
                className: 'poi-focus-popup'
            })
                    .setLngLat([poi.longitude, poi.latitude])
                    .setHTML(`<div class="poi-focus-content">${poi.name}</div>`)
                    .addTo(this.mbMap);

            // 3秒后自动关闭弹窗
            setTimeout(() => {
                if (popup.isOpen()) {
                    popup.remove();
                }
            }, 3000);
        }
    }

    executeSearch (containerId, bounds = [], callback) {
        // 通过容器ID获取输入框元素
        const inputElement = document.getElementById(containerId);
        if (!inputElement) {
            console.error(`未找到ID为 ${containerId} 的输入框元素`);
            return;
        }
        // 获取输入框的值作为搜索关键词
        const keyword = inputElement.value.trim();
        if (!keyword) return;

        // 天地图POI搜索API URL (使用注释中的v2/search接口)
        const baseUrl = 'https://api.tianditu.gov.cn/v2/search';

        // 构建请求参数 (按照注释中的格式)
        const postStr = {
            keyWord: keyword,
            level: 12,
            queryType: 1,
            start: 0,
            count: 100
        };

        // 如果提供了搜索范围，则添加边界参数
        if (bounds && bounds.length === 4) {
            postStr.mapBound = `${bounds[0]},${bounds[1]},${bounds[2]},${bounds[3]}`;
        } else {
            postStr.mapBound = `${mapConfig.mapExtent[0]},${mapConfig.mapExtent[1]},${mapConfig.mapExtent[2]},${mapConfig.mapExtent[3]}`;
        }

        // 构建完整的请求URL
        const params = new URLSearchParams({
            postStr: JSON.stringify(postStr),
            type: 'query',
            tk: TokenUtils.TDT_token
        });

        // 发送请求
        fetch(`${baseUrl}?${params.toString()}`)
                .then(response => response.json())
                .then(data => {
                    if (data.pois) {
                        // 处理返回的数据，转换为统一格式
                        const poiList = data.pois.map(item => ({
                            id: item.lonlat ? item.lonlat.split(',')[1] : '', // 使用lonlat生成ID
                            name: item.name,
                            address: item.address || '',
                            longitude: item.lonlat ? parseFloat(item.lonlat.split(',')[0]) : 0,
                            latitude: item.lonlat ? parseFloat(item.lonlat.split(',')[1]) : 0,
                            tel: item.phone || '',
                            type: item.type || ''
                        }));

                        // 使用Mapbox绘制POI结果
                        this.drawPOIResults(poiList);

                        callback && callback(poiList);
                    } else {
                        this.clearPOIResults();
                        callback && callback([]);
                    }
                })
                .catch(error => {
                    console.error('天地图POI搜索失败:', error);
                    this.clearPOIResults();
                    callback && callback([]);
                });
    }

    /**
     * 绘制POI搜索结果到地图上
     * @param {Array} poiList - POI结果列表
     */
    drawPOIResults (poiList) {
        if (!this.mbMap || !poiList || !poiList.length) return;

        // 清除之前的结果图层
        this.clearPOIResults();

        // 创建GeoJSON数据
        const geojson = {
            type: 'FeatureCollection',
            features: poiList.map(poi => ({
                type: 'Feature',
                geometry: {
                    type: 'Point',
                    coordinates: [poi.longitude, poi.latitude]
                },
                properties: {
                    id: poi.id,
                    name: poi.name,
                    address: poi.address,
                    tel: poi.tel,
                    type: poi.type
                }
            }))
        };

        // 添加数据源
        this.mbMap.addSource('poi-results', {
            type: 'geojson',
            data: geojson
        });

        // 添加点图层
        this.mbMap.addLayer({
            id: 'poi-results',
            type: 'circle',
            source: 'poi-results',
            paint: {
                'circle-radius': 8,
                'circle-color': '#ff6b35',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff'
            }
        });

        // 添加标签图层
        this.mbMap.addLayer({
            id: 'poi-labels',
            type: 'symbol',
            source: 'poi-results',
            layout: {
                'text-field': ['get', 'name'],
                'text-offset': [0, 1.5],
                'text-anchor': 'top',
                'text-size': 12
            },
            paint: {
                'text-color': '#333333',
                'text-halo-color': '#ffffff',
                'text-halo-width': 1
            }
        });

        // 添加点击事件
        this.mbMap.on('click', 'poi-results', (e) => {
            const feature = e.features[0];
            new mapboxgl.Popup({ offset: [0, -15] })
                    .setLngLat(feature.geometry.coordinates)
                    .setHTML(`                <div style="padding: 10px;">
                    <h3 style="margin: 0 0 5px 0;">${feature.properties.name}</h3>
                    <p style="margin: 5px 0;"><strong>地址:</strong> ${feature.properties.address || '无'}</p>
                    <p style="margin: 5px 0;"><strong>电话:</strong> ${feature.properties.tel || '无'}</p>
                    <p style="margin: 5px 0;"><strong>类型:</strong> ${feature.properties.type || '未知'}</p>
                </div>
            `)
                    .addTo(this.mbMap);
        });

        // 设置鼠标悬停效果
        this.mbMap.on('mouseenter', 'poi-results', () => {
            this.mbMap.getCanvas().style.cursor = 'pointer';
        });

        this.mbMap.on('mouseleave', 'poi-results', () => {
            this.mbMap.getCanvas().style.cursor = '';
        });
    }

    /**
     * 清除POI搜索结果
     */
    clearPOIResults () {
        if (!this.mbMap) return;

        if (this.mbMap.getLayer('poi-results')) {
            this.mbMap.removeLayer('poi-results');
        }
        if (this.mbMap.getLayer('poi-labels')) {
            this.mbMap.removeLayer('poi-labels');
        }
        if (this.mbMap.getSource('poi-results')) {
            this.mbMap.removeSource('poi-results');
        }

        // 移除事件监听器
        this.mbMap.off('click', 'poi-results');
        this.mbMap.off('mouseenter', 'poi-results');
        this.mbMap.off('mouseleave', 'poi-results');
    }

    /**
     * 转换数据点为地图点
     */
    getMapboxPoints (data) {
        if (!data) return [];
        return data.map(item => [item.longitude, item.latitude]);
    }

    /**
     * 标记点位并支持拖拽移动
     * @param {Object} map - 地图实例
     * @param {Array|Object} points - 点位数据
     * @param {Boolean} disableDrag - 是否禁用拖拽功能
     * @param {Function} onDragEnd - 拖拽结束回调函数，返回更新后的点位信息
     */
    hitPoint (map, points, disableDrag = true, onDragEnd) {
        if (!map) return;

        let pointsArray = Array.isArray(points) ? points : [points];

        // 创建点数据源
        const features = pointsArray
                .filter(point => point.longitude && point.latitude)
                .map(point => ({
                    type: 'Feature',
                    geometry: {
                        type: 'Point',
                        coordinates: [point.longitude, point.latitude]
                    },
                    properties: {
                        id: point.id,
                        patrolPoint: point.patrolPoint
                    }
                }));

        // 添加数据源和图层
        if (!map.getSource('hit-points')) {
            map.addSource('hit-points', {
                type: 'geojson',
                data: {
                    type: 'FeatureCollection',
                    features: features
                }
            });

            map.addLayer({
                id: 'hit-points',
                type: 'circle',
                source: 'hit-points',
                paint: {
                    'circle-radius': 6,
                    'circle-color': '#3a6bdb',
                    'circle-stroke-width': 2,
                    'circle-stroke-color': '#ffffff'
                }
            });

            // 添加标签
            map.addLayer({
                id: 'hit-point-labels',
                type: 'symbol',
                source: 'hit-points',
                layout: {
                    'text-field': ['get', 'patrolPoint'],
                    'text-offset': [0, 1.5],
                    'text-anchor': 'top'
                },
                paint: {
                    'text-color': '#0093ff'
                }
            });

            // 如果不禁用拖拽，则添加拖拽功能
            if (!disableDrag) {
                this._enablePointDragging(map, onDragEnd);
            }

            // 将 disableDrag 状态存储在图层上，便于后续更新时判断
            map.getLayer('hit-points')._disableDrag = disableDrag;
        } else {
            // 更新数据
            map.getSource('hit-points').setData({
                type: 'FeatureCollection',
                features: features
            });

            // 检查是否需要更新拖拽功能状态
            const hitPointsLayer = map.getLayer('hit-points');
            if (hitPointsLayer && hitPointsLayer._disableDrag !== disableDrag) {
                if (!disableDrag) {
                    // 启用拖拽功能
                    this._enablePointDragging(map, onDragEnd);
                } else {
                    // 禁用拖拽功能，移除相关事件监听器
                    map.off('mousedown', 'hit-points');
                    map.off('mouseenter', 'hit-points');
                    map.off('mouseleave', 'hit-points');
                }
                // 更新状态
                hitPointsLayer._disableDrag = disableDrag;
            }
        }
    }

    /**
     * 启用点位拖拽功能
     * @param {Object} map - 地图实例
     * @param {Function} onDragEnd - 拖拽结束回调函数
     */
    _enablePointDragging (map, onDragEnd) {
        let isDragging = false;
        let dragTarget = null;
        let originalPosition = null;
        let tooltip = null; // 添加tooltip变量

        // 鼠标按下事件 - 开始拖拽
        map.on('mousedown', 'hit-points', (e) => {
            this.enableScrollWheelZoom(false)
            map.dragPan.disable();
            isDragging = true;
            dragTarget = e.features[0];
            originalPosition = dragTarget.geometry.coordinates.slice();

            // 设置鼠标样式
            map.getCanvas().style.cursor = 'grabbing';

            // 为dragTarget增加一个tooltip
            tooltip = new mapboxgl.Popup({
                closeButton: false,
                closeOnClick: false,
                className: 'drag-tooltip'
            })
                    .setLngLat(dragTarget.geometry.coordinates)
                    .setHTML('<div>拖拽中...</div>')
                    .addTo(map);
        });

        // 鼠标移动事件 - 执行拖拽
        map.on('mousemove', (e) => {
            if (!isDragging || !dragTarget) return;

            // 更新点位位置
            const updatedFeatures = map.getSource('hit-points')._data.features.map(feature => {
                if (feature.properties.id === dragTarget.properties.id) {
                    return {
                        ...feature,
                        geometry: {
                            ...feature.geometry,
                            coordinates: [e.lngLat.lng, e.lngLat.lat]
                        }
                    };
                }
                return feature;
            });

            // 更新数据源
            map.getSource('hit-points').setData({
                type: 'FeatureCollection',
                features: updatedFeatures
            });

            // 更新tooltip位置
            if (tooltip) {
                tooltip.setLngLat([e.lngLat.lng, e.lngLat.lat]);
            }
        });

        // 鼠标释放事件 - 结束拖拽
        map.on('mouseup', () => {
            // 移除tooltip
            if (tooltip) {
                tooltip.remove();
                tooltip = null;
            }
            if (isDragging && dragTarget) {
                isDragging = false;

                // 获取更新后的点位数据
                const updatedFeatures = map.getSource('hit-points')._data.features;
                const updatedPoint = updatedFeatures.find(
                        feature => feature.properties.id === dragTarget.properties.id
                );

                // 调用回调函数返回更新后的点位信息
                if (onDragEnd && updatedPoint) {
                    onDragEnd({
                        id: updatedPoint.properties.id,
                        patrolPoint: updatedPoint.properties.patrolPoint,
                        longitude: updatedPoint.geometry.coordinates[0],
                        latitude: updatedPoint.geometry.coordinates[1],
                        originalLongitude: originalPosition[0],
                        originalLatitude: originalPosition[1]
                    });
                }

                dragTarget = null;
                originalPosition = null;

                this.enableScrollWheelZoom()
                map.dragPan.enable();
            }

            // 恢复鼠标样式
            map.getCanvas().style.cursor = '';
        });

        // 鼠标离开地图时也结束拖拽
        map.on('mouseleave', () => {
            if (isDragging) {
                isDragging = false;
                dragTarget = null;
                originalPosition = null;

                // 移除tooltip
                if (tooltip) {
                    tooltip.remove();
                    tooltip = null;
                }

                map.getCanvas().style.cursor = '';
            }
        });

        // 设置鼠标悬停样式
        map.on('mouseenter', 'hit-points', () => {
            map.getCanvas().style.cursor = 'grab';
        });

        map.on('mouseleave', 'hit-points', () => {
            if (!isDragging) {
                map.getCanvas().style.cursor = '';
            }
        });
    }

    /**
     * 绘制线
     */
    renderLine (map, points, options) {
        if (!map || !points || points.length < 2) return;

        const coordinates = points.map(p => [p.lng, p.lat]);

        const config = {
            enableEditing: false,
            enableClicking: true,
            strokeWeight: 5,
            strokeOpacity: 0.65,
            ...options
        };

        // 创建线数据源
        if (!map.getSource('custom-line')) {
            map.addSource('custom-line', {
                type: 'geojson',
                data: {
                    type: 'Feature',
                    geometry: {
                        type: 'LineString',
                        coordinates: coordinates
                    },
                    properties: {}
                }
            });

            map.addLayer({
                id: 'custom-line',
                type: 'line',
                source: 'custom-line',
                paint: {
                    'line-color': '#3a6bdb',
                    'line-width': config.strokeWeight,
                    'line-opacity': config.strokeOpacity
                }
            });
        } else {
            // 更新数据
            map.getSource('custom-line').setData({
                type: 'Feature',
                geometry: {
                    type: 'LineString',
                    coordinates: coordinates
                },
                properties: {}
            });
        }

        return map.getLayer('custom-line');
    }

    /**
     * controls
     */
    /**
     * 启用滚轮缩放
     * @param {boolean} isOpen 是否开启控制
     */
    enableScrollWheelZoom (isOpen = true) {
        // 进行mapboxgl的scroll(wheel)事件的控制
        if (!this.mbMap) return;

        if (isOpen) {
            this.mbMap.scrollZoom.enable();
        } else {
            this.mbMap.scrollZoom.disable();
        }
    }

    /**
     * 绘制带中心点标注的经纬度网格
     * @param {Object} map - 地图实例
     * @param {Object} options - 网格配置选项
     */
    _drawGridWithCenterLabels (map, options = {}) {
        if (!map) return;

        const {
            interval = 1,
            color = '#0066cc',
            width = 1,
            showLabels = true,
            showCenterLabels = true
        } = options;

        const features = [];
        const labelFeatures = [];
        const centerLabelFeatures = [];

        // 中国范围经纬度网格
        // 73.55, 3.85, 135.08, 53.55
        const minLng = mapConfig.mapExtent[0], maxLng = mapConfig.mapExtent[2];
        const minLat = mapConfig.mapExtent[1], maxLat = mapConfig.mapExtent[3];

        // 经线
        for (let lng = Math.ceil(minLng); lng <= Math.floor(maxLng); lng += interval) {
            const coordinates = [];
            for (let lat = minLat; lat <= maxLat; lat += 0.1) {
                coordinates.push([lng, lat]);
            }
            features.push({
                type: 'Feature',
                geometry: {
                    type: 'LineString',
                    coordinates: coordinates
                },
                properties: {
                    type: 'longitude',
                    value: lng
                }
            });

            // 添加经度标签
            if (showLabels) {
                labelFeatures.push({
                    type: 'Feature',
                    geometry: {
                        type: 'Point',
                        coordinates: [lng, minLat]
                    },
                    properties: {
                        text: `${lng}°`
                    }
                });
            }
        }

        // 纬线
        for (let lat = Math.ceil(minLat); lat <= Math.floor(maxLat); lat += interval) {
            const coordinates = [];
            for (let lng = minLng; lng <= maxLng; lng += 0.1) {
                coordinates.push([lng, lat]);
            }
            features.push({
                type: 'Feature',
                geometry: {
                    type: 'LineString',
                    coordinates: coordinates
                },
                properties: {
                    type: 'latitude',
                    value: lat
                }
            });

            // 添加纬度标签
            if (showLabels) {
                labelFeatures.push({
                    type: 'Feature',
                    geometry: {
                        type: 'Point',
                        coordinates: [minLng, lat]
                    },
                    properties: {
                        text: `${lat}°`
                    }
                });
            }
        }

        // 添加网格中心点标签（显示经纬度区间）
        if (showCenterLabels) {
            for (let lng = Math.ceil(minLng); lng < Math.floor(maxLng); lng += interval) {
                for (let lat = Math.ceil(minLat); lat < Math.floor(maxLat); lat += interval) {
                    // 计算网格中心点
                    const centerLng = lng + interval / 2;
                    const centerLat = lat + interval / 2;

                    // 创建区间标签文本
                    const label = `${lng}°~${lng + interval}°\n${lat}°~${lat + interval}°`;

                    centerLabelFeatures.push({
                        type: 'Feature',
                        geometry: {
                            type: 'Point',
                            coordinates: [centerLng, centerLat]
                        },
                        properties: {
                            text: label
                        }
                    });
                }
            }
        }

        // 添加网格线数据源和图层
        if (!map.getSource('longitude-latitude-grid')) {
            map.addSource('longitude-latitude-grid', {
                type: 'geojson',
                data: {
                    type: 'FeatureCollection',
                    features: features
                }
            });

            map.addLayer({
                id: 'longitude-latitude-grid',
                type: 'line',
                source: 'longitude-latitude-grid',
                paint: {
                    'line-color': color,
                    'line-width': width,
                    'line-opacity': 0.6,
                    'line-dasharray': [2, 2]
                }
            });
        } else {
            map.getSource('longitude-latitude-grid').setData({
                type: 'FeatureCollection',
                features: features
            });
        }

        // 添加边界标签数据源和图层
        if (showLabels && labelFeatures.length > 0) {
            if (!map.getSource('grid-labels')) {
                map.addSource('grid-labels', {
                    type: 'geojson',
                    data: {
                        type: 'FeatureCollection',
                        features: labelFeatures
                    }
                });

                map.addLayer({
                    id: 'grid-labels',
                    type: 'symbol',
                    source: 'grid-labels',
                    layout: {
                        'text-field': ['get', 'text'],
                        'text-size': 16,
                        'text-offset': [0, 1]
                    },
                    paint: {
                        'text-color': '#ff6b35',
                        'text-halo-color': '#ffffff',
                        'text-halo-width': 1,
                    }
                });
            } else {
                map.getSource('grid-labels').setData({
                    type: 'FeatureCollection',
                    features: labelFeatures
                });
            }
        }

        // 添加中心点区间标签数据源和图层（仅在层级10及以上显示）
        if (showCenterLabels && centerLabelFeatures.length > 0) {
            if (!map.getSource('grid-center-labels')) {
                map.addSource('grid-center-labels', {
                    type: 'geojson',
                    data: {
                        type: 'FeatureCollection',
                        features: centerLabelFeatures
                    }
                });

                map.addLayer({
                    id: 'grid-center-labels',
                    type: 'symbol',
                    source: 'grid-center-labels',
                    layout: {
                        'text-field': ['get', 'text'],
                        'text-size': 16,
                        'text-offset': [0, 0],
                        'text-anchor': 'center',
                        'text-justify': 'center',
                    },
                    paint: {
                        'text-color': '#ff6b35',
                        'text-halo-color': '#ffffff',
                        'text-halo-width': 1,
                    }
                });
            } else {
                map.getSource('grid-center-labels').setData({
                    type: 'FeatureCollection',
                    features: centerLabelFeatures
                });
            }
        }
    }

    /**
     * 清除经纬度网格（包括中心点标签）
     * @param {Object} map - 地图实例
     */
    clearGridWithCenterLabels (map) {
        if (!map) return;

        // 清除网格线
        if (map.getLayer('longitude-latitude-grid')) {
            map.removeLayer('longitude-latitude-grid');
        }
        if (map.getSource('longitude-latitude-grid')) {
            map.removeSource('longitude-latitude-grid');
        }

        // 清除边界标签
        if (map.getLayer('grid-labels')) {
            map.removeLayer('grid-labels');
        }
        if (map.getSource('grid-labels')) {
            map.removeSource('grid-labels');
        }

        // 清除中心点标签
        if (map.getLayer('grid-center-labels')) {
            map.removeLayer('grid-center-labels');
        }
        if (map.getSource('grid-center-labels')) {
            map.removeSource('grid-center-labels');
        }
    }

    /**
     * 计算线段中间点
     * @param start
     * @param end
     * @returns {{lng, lat}}
     */
    countMidFromLine(start, end) {
        return {
            lng: (start.lng + end.lng) / 2,
            lat: (start.lat + end.lat) / 2
        };
    }
    /**
     * 清除所有非底图图层
     */

    clearOverlays () {
        // 批量清除所有巡检相关的动态图层（ID包含patrol-track-前缀）
        const layers = map.getStyle().layers;
        layers.forEach(layer => {
            if (layer.id.includes('patrol-track-')) {
                map.removeLayer(layer.id);
                if (layer.source && layer.source.includes('patrol-track-')) {
                    map.removeSource(layer.source);
                }
            }
        });
    }
}

// 导出单例实例
const mapboxNative = new MapboxNative();
export default mapboxNative;
