import qs from 'qs'
import { merge, omit } from 'lodash-es'
import {
    HandlerUtil,
    buildTileJsonURL,
    defaultStyle,
    loadMapControl,
    loadMapboxLibs,
    sendRequest,
} from '/@/components/Map/Mapbox'

// renderjs 官方文档
// https://uniapp.dcloud.io/tutorial/renderjs.html
// renderjs 的一些细节问题
// https://juejin.cn/post/7049185827582115870

function replaceVariables(str, data) {
    if (!HandlerUtil.isPlainObject(data)) {
        return str
    }

    // 使用正则表达式匹配 {a.xxx} 格式的变量占位字符串
    const regex = /\{inject\.(\w+)\}/g

    // 使用 replace 方法进行替换
    const result = str.replace(regex, (match, key) => {
        // 检查变量是否存在于提供的数据对象中
        if (data[key]) {
            return data[key]
        }
        // 如果变量不存在，则返回原始占位字符串
        return match
    })

    return result
}

async function request(url, handler) {
    const { origin, pathname, search } = new URL(url)
    const query = qs.parse(search, { ignoreQueryPrefix: true })
    const params = qs.stringify({ ...query, inject: undefined }, { addQueryPrefix: true, encode: true })
    const data = await sendRequest(`${origin}${pathname}${params}`)

    const { body } = data
    if (handler) {
        // eslint-disable-next-line no-eval
        const executableFunction = window.eval(`(${replaceVariables(handler, query?.inject)})`)
        return { data: executableFunction(body, HandlerUtil), raw: body }
    }

    return { data: body, raw: body }
}

// 全局暴露 popup 事件处理方法
window.onPopupContentEventHandle = function (e) {
    if (popupFeature && $vm) {
        // 获取当前 popup 点位的图层和属性
        const layer = popupFeature.layer.id
        const properties = popupFeature.properties
        delete properties.popup

        // 调用逻辑层方法
        $vm.$ownerInstance.callMethod('onEventHandle', {
            type: 'custom',
            name: e ? 'src' : 'timing',
            data: {
                type: 'click',
                layer,
                properties,
                url: e,
            },
        })
    }
}

// 全局暴露 navigateToDetail 方法，供 popup 中的按钮调用
window.navigateToDetail = function (data) {
    if ($vm) {
        // 调用逻辑层方法，通过 onEventHandle 传递事件
        $vm.$ownerInstance.callMethod('onEventHandle', {
            type: 'custom',
            name: 'navigateToDetail',
            data,
        })
    }
}

const defaultEmptyGeoJSON = {
    type: 'FeatureCollection',
    features: [],
}

let $vm = null
let popup = null
let popupFeature = null
export default {
    data() {
        return {
            config: {},
            listeners: {},
            markers: {},
        }
    },
    mounted() {
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        $vm = this
    },
    methods: {
        loadLibs: loadMapboxLibs,
        initMap(options) {
            // 移除地图
            if (this.map && this.map.remove) {
                this.map.remove()
            }
            console.log(123123, merge(defaultStyle, options?.style))
            // [107.570282, 19.474339],
            // [115.629717, 34.466859],

            // 加载地图
            const mapboxgl = window.mapboxgl
            const map = new mapboxgl.Map({
                // accessToken,
                container: options.container,
                style: merge(defaultStyle, options?.style),
                ...merge(
                    {
                        minZoom: 5,
                        maxZoom: 18,
                        maxBounds: [
                            [106.94, 20.89],
                            [117.03, 34],
                        ],
                    },
                    options?.options,
                ),
                // 禁用默认的 attribution 控件
                attributionControl: false,
                // 禁用旋转
                dragRotate: false,
                touchRotate: false,
                // 禁用倾斜
                pitchWithRotate: false,
                // 不同源的冲突碰撞检测
                crossSourceCollisions: false,
                // 启用本地字体
                // localFontFamily: true,

                // 默认使用 equirectangular(等经纬度) 投影
                projection: options?.options?.projection || 'equirectangular',
            })

            // 绑定作用域
            this.map = map

            // 监听地图错误事件
            map.on('error', (e) => {
                console.error('Mapbox map error', e)
            })

            // 监听地图事件
            map.once('styledata', function () {
                // 禁用旋转
                map.dragRotate.disable()
                map.touchPitch.disable()
                map.touchZoomRotate.disableRotation()
            })

            // 加载地图控件
            map.on('load', () => {
                // console.log(map.getCenter())

                // #ifdef APP-PLUS
                if (options?.extra?.control?.geolocate) {
                    window.navigator.permissions = undefined
                    options.extra.control.geolocate = {
                        ...options.extra.control.geolocate,
                        geolocation: {
                            getCurrentPosition: (onPositionSuccess, _onPositionError, options) => {
                                this.onPositionSuccess = onPositionSuccess
                                this.$ownerInstance.callMethod('getCurrentPosition', options)
                            },
                        },
                    }
                }
                // #endif
                // 加载地图图层
                this.initMapLayers(this.config)
                    .then(() => {
                        // 添加地图数据来源描述
                        if (options.attribution) {
                            map.addControl(
                                new mapboxgl.AttributionControl({
                                    compact: true,
                                    customAttribution: options.attribution?.text,
                                }),
                                options.attribution?.align || 'bottom-right',
                            )
                        }

                        // 加载地图控件
                        loadMapControl(mapboxgl, map, options?.extra?.control)

                        // 调用逻辑层方法
                        this.loaded = true
                        console.debug('Mapbox map loaded', map)
                        this.$ownerInstance.callMethod('onMapLoad', {
                            center: map.getCenter(),
                        })
                    })
                    .catch(console.error)
            })
        },
        initMapLayers({ region, regionConfig, autoFlyToRegionCenter, options }) {
            // TODO
            // 1. 检查遮罩数据源是否存在，不存在则添加，存在则先移除再添加
            // 2. 检查遮罩图层是否存在，不存在则添加，存在则先移除再添加
            // 3. 对一些数据图层进行过滤，只显示当前区域的数据
            // 4. 重置地图中心点和缩放级别
            if (region && regionConfig) {
                const { properties = {}, cityCode } = regionConfig
                const id = properties?.code

                if (!id) {
                    return Promise.resolve()
                }

                // 检查遮罩图层是否存在，存在则先移除

                if (this.map.getLayer('line')) {
                    this.map.removeLayer(`line`)
                    this.map.removeLayer(`mask`)
                    this.map.removeLayer(`shadow`)
                }

                if (this.map.getSource(id)) {
                    this.map.removeSource(id)
                    this.map.removeSource(`${id}.mask`)
                }

                // 添加边界数据源
                this.map.addSource(id, {
                    type: 'vector',
                    url: buildTileJsonURL(`${id}.v2024`),
                })

                // 添加遮罩数据源
                if (!options?.noMusk) {
                    this.map.addSource(`${id}.mask`, {
                        type: 'vector',
                        url: buildTileJsonURL(`${id}.v2024.mask`),
                    })
                    // 添加遮罩图层
                    this.map.addLayer(
                        {
                            id: `mask`,
                            type: 'fill',
                            source: `${id}.mask`,
                            'source-layer': `${id}.v2024.mask`,
                            paint: {
                                'fill-color': '#F4F5F7',
                            },
                        },
                        'mask-placeholder',
                    )
                }
                // 添加阴影图层
                this.map.addLayer(
                    {
                        id: `shadow`,
                        type: 'line',
                        source: id,
                        'source-layer': `${id}.v2024`,
                        layout: {
                            'line-join': 'round',
                            'line-cap': 'round',
                        },
                        paint: {
                            'line-width': 4,
                            'line-blur': 92.7,
                            'line-offset': -4,
                            'line-color': '#444',
                        },
                    },
                    'mask-placeholder',
                )
                // 添加边界图层
                this.map.addLayer(
                    {
                        id: `line`,
                        source: id,
                        'source-layer': `${id}.v2024`,
                        type: 'line',
                        paint: {
                            'line-width': 2,
                            'line-color': '#444',
                        },
                    },
                    'mask-placeholder',
                )

                // 解析区域编码
                const splits = region.match(/.{1,2}/g)
                if (splits && splits.length > 0) {
                    // 解构省市区编码
                    const [_, city, area] = splits

                    // 视角飞行到最佳位置
                    if (autoFlyToRegionCenter !== false) {
                        this.map.flyTo({
                            center: [properties.lat, properties.lon],
                            zoom: properties.zoom || (area ? 7.8 : city ? 6.5 : 5.5),
                            essential: true,
                            // speed: 0.2,
                            duration: 0,
                        })
                    }

                    // 重置图层过滤
                    this.map.setFilter(`430000.city-label`, null)
                    this.map.setFilter(`430000.area-label`, null)
                    this.map.setFilter(`430000.town-label`, null)

                    // 图层数据过滤
                    if (area) {
                        this.map.setLayoutProperty('430000.city-label', 'visibility', 'none')
                        this.map.setLayoutProperty('430000.area-label', 'visibility', 'visible')
                        this.map.setFilter(`430000.area-label`, [
                            'all',
                            ['==', ['get', 'city'], city],
                            ['==', ['get', 'area'], area],
                        ])
                        this.map.setFilter(`430000.town-label`, [
                            'all',
                            ['==', ['get', 'city'], city],
                            ['==', ['get', 'area'], area],
                        ])
                    } else if (city) {
                        this.map.setLayoutProperty('430000.city-label', 'visibility', 'visible')
                        this.map.setLayoutProperty('430000.area-label', 'visibility', 'visible')
                        this.map.setFilter(`430000.city-label`, ['==', ['get', 'city'], city])
                        this.map.setFilter(`430000.area-label`, ['==', ['get', 'city'], city])
                        this.map.setFilter(`430000.town-label`, ['==', ['get', 'city'], city])
                    } else {
                        this.map.setLayoutProperty('430000.city-label', 'visibility', 'visible')
                        this.map.setLayoutProperty('430000.area-label', 'visibility', 'visible')
                    }

                    if (cityCode) {
                        this.map.setFilter(`430000.city-line-select`, ['all', ['==', ['get', 'code'], `${cityCode}00`]])
                        this.map.setLayoutProperty('430000.city-line-select', 'visibility', 'visible')
                    }

                    setTimeout(() => {
                        this.map.setLayoutProperty('430000.city-line', 'visibility', 'visible')
                        this.map.setLayoutProperty('430000.area-line', 'visibility', 'visible')
                        this.map.setLayoutProperty('430000.town-line', 'visibility', 'visible')
                    }, 500)
                }
            }

            return Promise.resolve()
        },
        // 检测触发变更时候的有效性
        checkOnChangeValidity(options) {
            if (options && Object.keys(options).length > 0 && this.map) {
                // 移除弹窗
                this.clearPopup()
                options.fn && this.emitChangeEvent(options.fn)
                return true
            }
            return false
        },
        emitChangeEvent(type) {
            // 通知逻辑层，本次变更事件已经送达
            this.$ownerInstance.callMethod('onMapOptionsChangeEvent', { type })
        },
        changeOptions(options) {
            if (!options.container) {
                return
            }

            this.config = options
            if (typeof window.mapboxgl === 'object') {
                this.initMap(options)
            } else {
                this.loadLibs().then(() => {
                    this.initMap(options)
                })
            }
        },
        changeRegionOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.initMapLayers(options).then(() => {
                    this.config.region = options.region
                    this.config.regionConfig = options.regionConfig
                    this.config.autoFlyToRegionCenter = options.flyTo
                })
            }
        },
        changeFlyToOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.flyTo(options)
            }
        },
        changeAddSourceOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                if (this.map.getSource(options.id)) {
                    this.map.getSource(options.id).setData(options.source.data)
                } else {
                    this.map.addSource(options.id, options.source)
                }
            }
        },
        changeSetGeoJSONSourceForRequestOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                if (this.map.getSource(options.id)) {
                    // 移除弹窗
                    this.clearPopup()
                    // 清空数据
                    this.map.getSource(options.id).setData(defaultEmptyGeoJSON)
                } else {
                    // 添加空的 source
                    this.map.addSource(options.id, {
                        type: 'geojson',
                        data: defaultEmptyGeoJSON,
                    })
                }

                // 请求数据
                request(options.url, options.handler)
                    .then(({ data, raw }) => {
                        this.map.getSource(options.id).setData(data)
                        this.$ownerInstance.callMethod('onSourceRequestHandle', {
                            id: options.id,
                            url: options.url,
                            data: omit(raw, options.filters || []),
                        })
                    })
                    .catch((e) => {
                        console.error(e)
                        this.$ownerInstance.callMethod('onSourceRequestErrorHandle', e.message)
                    })
            }
        },
        changeSetGeoJSONSourceDataOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.getSource(options.id).setData(options.data)
            }
        },
        changeSetVectorTileSourceTilesOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.getSource(options.id).setTiles(options.tiles)
            }
        },
        changeUpdateRasterImageOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.getSource(options.id).updateImage({
                    url: options.url,
                })
            }
        },
        changeAddLayerOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                if (this.map.getLayer(options.layer.id)) {
                    this.map.removeLayer(options.layer.id)
                }
                this.map.addLayer(options.layer, options.beforeId)

                if (options.popup && ['symbol', 'fill', 'line'].includes(options.layer.type)) {
                    this.map.on('click', options.layer.id, (e) => {
                        const feature = e.features[0]
                        if (feature && feature.properties?.popup) {
                            popupFeature = feature
                            popup = new window.mapboxgl.Popup()
                                .setLngLat(options.layer.type === 'symbol' ? feature.geometry.coordinates : e.lngLat)
                                .setHTML(
                                    feature.properties.popup
                                        .replace('{key}', feature.properties.key)
                                        .replace('{value}', feature.properties.value)
                                        .replace('{suffix}', feature.properties.suffix || '')
                                        .replace(
                                            '{{timing}}',
                                            `<button onclick="onPopupContentEventHandle()"><i class="icon"></i>查看时序</button>`,
                                        )
                                        .replace(
                                            '{{download}}',
                                            `<button onclick="onPopupContentEventHandle()"><i class="icon"></i>下载视频</button>`,
                                        )
                                        .replaceAll(/\{\{(\w+)\}}/g, (_, i) => feature.properties[i]),
                                )
                                .addTo(this.map)
                        }
                    })
                }
            }
        },
        changeRemoveOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                if (options.type === 'layer') {
                    if (this.map.getLayer(options.id)) {
                        this.map.removeLayer(options.id)
                    }
                } else if (options.type === 'source') {
                    if (this.map.getSource(options.id)) {
                        this.map.removeSource(options.id)
                    }
                } else if (options.type === 'marker') {
                    this.markers[options.id]?.remove()
                } else if (options.type === 'popup') {
                    this.clearPopup()
                }
            }
        },
        changeSetFilterOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.setFilter(options.layerId, options.filter)
            }
        },
        changeSetLayoutPropertyOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.setLayoutProperty(options.layerId, options.layoutProperty, options.value)
            }
        },
        changeSetPaintPropertyOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                this.map.setPaintProperty(options.layerId, options.paintProperty, options.value)
            }
        },
        changeEventOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                const key = `on_${options.type}_${options.layer}`
                if (options.event === 'on') {
                    this.listeners[key] = (e) => {
                        console.debug('🔔 Map event on', options.type, e)
                        this.$ownerInstance.callMethod('onEventHandle', {
                            type: options.type,
                            layer: options.layer,
                            event: {
                                lngLat: e.lngLat,
                                features: e.features,
                            },
                        })
                    }

                    if (!options.layer || options.layer === 'all') {
                        this.map.on(options.type, this.listeners[key])
                    } else {
                        this.map.on(options.type, options.layer, this.listeners[key])
                    }
                } else if (options.event === 'off') {
                    console.debug('🔦 Map event off', options.type)
                    this.map.off(options.type, this.listeners[key])
                }
            }
        },
        changeAddMarkerOptions(options) {
            if (this.checkOnChangeValidity(options)) {
                const { id, lngLat, popup, popupDefaultOpen, element, imageUrl, iconSize, ...rest } = options
                if (this.markers[id]) {
                    this.markers[id].remove()
                }

                let markerElement = element
                
                // 如果提供了图片URL，创建自定义元素
                if (imageUrl && !element) {
                    markerElement = document.createElement('div')
                    markerElement.className = 'custom-marker'
                    markerElement.style.backgroundImage = `url(${imageUrl})`
                    markerElement.style.width = iconSize ? `${iconSize[0]}px` : '40px'
                    markerElement.style.height = iconSize ? `${iconSize[1]}px` : '40px'
                    markerElement.style.backgroundSize = 'cover'
                    markerElement.style.borderRadius = '50%'
                    markerElement.style.cursor = 'pointer'
                    markerElement.style.border = '2px solid white'
                    markerElement.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)'
                }
                
                // 如果有自定义元素，使用它；否则使用默认配置
                const marker = markerElement 
                    ? new window.mapboxgl.Marker(markerElement).setLngLat(lngLat).addTo(this.map)
                    : new window.mapboxgl.Marker({ scale: 0.8, ...rest }).setLngLat(lngLat).addTo(this.map)
                
                if (popup) {
                    const popupComponent = new window.mapboxgl.Popup({ options: { closeButton: true } }).setHTML(popup)
                    marker.setPopup(popupComponent)

                    if (popupDefaultOpen) {
                        marker.togglePopup()
                    }
                }

                this.markers[id] = marker
            }
        },
        changePosition(position) {
            if (!this.loaded) {
                return
            }
            this.onPositionSuccess?.(position)
        },
        clearPopup() {
            // 移除弹窗
            if (popup) {
                popup.remove()
                popup = null
                popupFeature = null
            }
        },
    },
}
