import type mapboxgl from 'mapbox-gl'
import type { MapboxConfig, MapboxInstance } from './index'
import { isProdMode } from '@/utils/env'

// 组件名称
export const name = 'Mapbox'

/**
 * 注册 Mapbox 实例
 * @param config Mapbox 配置项
 */
export function useMapbox<T extends MapboxInstance, P extends MapboxConfig>(
    config: P,
): [(instance: T) => void, MapboxInstance] {
    const instanceRef = ref<T>()

    function register(instance: T) {
        if (isProdMode()) {
            if (instance === unref(instanceRef)) {
                return
            }

            onUnmounted(() => {
                instanceRef.value = null
            })
        }

        instanceRef.value = instance
        config && instance?.setConfig(config)
    }

    function getInstance() {
        const instance = unref(instanceRef)
        if (!instance) {
            console.warn('Mapbox instance is undefined!')
        }
        return instance as T
    }

    return [
        register,
        {
            setConfig: (config: Partial<P>) => getInstance()?.setConfig(config),
            isReady: computed(() => instanceRef?.value?.isReady) as unknown as ComputedRef<boolean>,

            on: (type: string, layerId: string, listener: (...args: any[]) => void) =>
                getInstance()?.on(type, layerId, listener),
            addSource: (id: string, source: mapboxgl.AnySourceData) => getInstance()?.addSource(id, source),
            removeSource: (id: string) => getInstance()?.removeSource(id),
            setGeoJSONSourceForRequest: (
                id: string,
                url: string,
                map: (
                    data: Recordable,
                ) => GeoJSON.Feature<GeoJSON.Geometry> | GeoJSON.FeatureCollection<GeoJSON.Geometry>,
            ) => getInstance()?.setGeoJSONSourceForRequest(id, url, map),
            setGeoJSONSourceData: (id: string, data: mapboxgl.GeoJSONSource['setData'], filter?: string) =>
                getInstance()?.setGeoJSONSourceData(id, data, filter),
            setVectorTileSourceTiles: (id: string, tiles: string[]) =>
                getInstance()?.setVectorTileSourceTiles(id, tiles),
            addLayer: (layer: mapboxgl.Layer) => getInstance()?.addLayer(layer),
            removeLayer: (id: string) => getInstance()?.removeLayer(id),
            setPaintProperty: (layerId: string, name: string, value: any) =>
                getInstance()?.setPaintProperty(layerId, name, value),
            setLayoutProperty: (layerId: string, name: string, value: any) =>
                getInstance()?.setLayoutProperty(layerId, name, value),
            setFilter: (layerId: string, filter: any[]) => getInstance()?.setFilter(layerId, filter),
            flyTo: (options: mapboxgl.FlyToOptions) => getInstance()?.flyTo(options),
        },
    ]
}

export function buildGeoJSONSourceDataUrl(config: { url: string; params: Recordable }): string {
    const { url, params } = config
    const keys = Object.keys(params)
    if (keys.length === 0) {
        return url
    }

    const query = keys.map((key) => `${key}=${params[key]}`).join('&')
    return `${url}?${query}`
}
