import * as Cesium from 'cesium'
import { SplitDirection } from 'cesium'

// 依赖：{ viewerOrThrow, store }
export function createLayerService(deps) {
  const { viewerOrThrow, store } = deps

  // 影像图层 zIndex 辅助函数
  function nextZIndex() {
    const zIndexValues = Object.values(store.layers)
      .filter((record) => record && record.type === 'imagery')
      .map((record) => (record.meta && typeof record.meta.zIndex === 'number' ? record.meta.zIndex : 0))
    return (zIndexValues.length ? Math.max(...zIndexValues) : 0) + 1
  }

  // 按 zIndex 重新整理影像图层的叠放顺序
  function adjustImageryOrder(viewer) {
    try {
      const imageryRecords = Object.values(store.layers)
        .filter((record) => record && record.type === 'imagery' && record.obj)
        .sort((a, b) => {
          const aZ = a.meta && typeof a.meta.zIndex === 'number' ? a.meta.zIndex : 0
          const bZ = b.meta && typeof b.meta.zIndex === 'number' ? b.meta.zIndex : 0
          return aZ - bZ
        })
      // raiseToTop in ascending order so the highest ends top-most
      imageryRecords.forEach((record) => {
        try {
          if (viewer.imageryLayers.contains(record.obj)) viewer.imageryLayers.raiseToTop(record.obj)
        } catch (e) {}
      })
      syncImageryOrderMeta(viewer)
    } catch (e) {}
  }

  /**
   * @description 同步影像图层元数据里的排序索引，保持与 Cesium 实际顺序一致
   */
  function syncImageryOrderMeta(viewer) {
    try {
      const imageryLayers = viewer.imageryLayers
      const imageryRecords = Object.values(store.layers)
        .filter((record) => record && record.type === 'imagery' && record.obj)
      const lookup = new Map()
      imageryRecords.forEach((record) => lookup.set(record.obj, record))
      const count = imageryLayers.length
      for (let i = 0; i < count; i += 1) {
        const layer = imageryLayers.get(i)
        const record = lookup.get(layer)
        if (!record) continue
        if (!record.meta) record.meta = {}
        record.meta.zIndex = i
      }
    } catch (e) {}
  }

  /**
   * @description 同步矢量数据源图层顺序，记录在 meta.vectorOrder 中
   */
  function syncVectorOrderMeta(viewer) {
    try {
      const dataSources = viewer.dataSources
      const vectorRecords = Object.values(store.layers)
        .filter((record) => record && (record.type === 'vector' || record.type === 'datasource') && record.obj)
      const lookup = new Map()
      vectorRecords.forEach((record) => lookup.set(record.obj, record))
      const count = dataSources.length
      for (let i = 0; i < count; i += 1) {
        const ds = dataSources.get(i)
        const record = lookup.get(ds)
        if (!record) continue
        if (!record.meta) record.meta = {}
        record.meta.vectorOrder = i
      }
    } catch (e) {}
  }

  return {
    async addLayer(spec) {
      const viewer = viewerOrThrow()

      // 兼容新旧两种参数风格（新的 serviceConfig 与旧的直传 spec）
      const layerSpec = spec
      const layerType = layerSpec.type
      const layerId = layerSpec.id || (layerType ? `${layerType}:${Date.now().toString(36)}` : `layer:${Date.now().toString(36)}`)
      if (store.layers[layerId]) return layerId

      const metadata = { ...(layerSpec.meta || {}) }
      if (layerSpec.zIndex != null) metadata.zIndex = Number(layerSpec.zIndex)
      if (metadata.zIndex == null && (layerType && layerType !== 'terrain' && layerType !== 'primitive' && layerType !== 'vector' && layerType !== 'datasource')) {
        metadata.zIndex = nextZIndex()
      }

      const layerOptions = layerSpec.options || {}
      const sourceUrl = layerSpec.url

      let layerRecord = null

      // 注册影像图层（ImageryLayer）的辅助方法
      const registerImageryLayer = (provider, extraProps = {}) => {
        const imageryLayer = viewer.imageryLayers.addImageryProvider(provider)
        if (typeof layerOptions.opacity === 'number') imageryLayer.alpha = layerOptions.opacity
        if (typeof layerOptions.visible === 'boolean') imageryLayer.show = layerOptions.visible
        imageryLayer.splitDirection = SplitDirection.NONE
        const record = {
          id: layerId,
          type: 'imagery',
          obj: imageryLayer,
          owned: true,
          show: imageryLayer.show,
          opacity: imageryLayer.alpha,
          meta: metadata,
          ...extraProps,
        }
        store.layers[layerId] = record
        adjustImageryOrder(viewer)
        return record
      }

      // 注册矢量数据源的辅助方法
      const registerVectorLayer = async (dataSource) => {
        await viewer.dataSources.add(dataSource)
        dataSource.show = layerOptions.visible !== false
        const record = {
          id: layerId,
          type: 'vector',
          obj: dataSource,
          owned: true,
          show: dataSource.show,
          opacity: typeof layerOptions.opacity === 'number' ? layerOptions.opacity : 1,
          meta: metadata,
        }
        store.layers[layerId] = record
        syncVectorOrderMeta(viewer)
        return record
      }

      // 旧版直映射类型分支
      if (layerType === 'imagery' || layerType === 'baseImagery') {
        const provider = layerSpec.source
        layerRecord = registerImageryLayer(provider)
        if (layerType === 'baseImagery') viewer.imageryLayers.lowerToBottom(layerRecord.obj)
        return layerId
      }
      if (layerType === 'vector' || layerType === 'datasource') {
        const dataSource = new Cesium.CustomDataSource(layerId)
        layerRecord = await registerVectorLayer(dataSource)
        return layerId
      }
      if (layerType === 'terrain') {
        if ('terrain' in viewer) viewer.terrain = layerSpec.source
        else viewer.scene.terrainProvider = layerSpec.source
        layerRecord = {
          id: layerId,
          type: 'terrain',
          obj: layerSpec.source,
          owned: true,
          show: true,
          opacity: 1,
          meta: metadata,
        }
        store.layers[layerId] = layerRecord
        return layerId
      }
      if (layerType === 'primitive') {
        const primitive = layerSpec.source
        viewer.scene.primitives.add(primitive)
        layerRecord = {
          id: layerId,
          type: 'primitive',
          obj: primitive,
          owned: true,
          show: true,
          opacity: 1,
          meta: metadata,
        }
        store.layers[layerId] = layerRecord
        return layerId
      }

      // React serviceConfig-style types
      switch (layerType) {
        case 'ArcGISTiledMapServiceLayer': {
          const haveTemplateXYZ = typeof sourceUrl === 'string' && sourceUrl.includes('{z}/{y}/{x}')
          if (!haveTemplateXYZ) {
            const provider = await Cesium.ArcGisMapServerImageryProvider.fromUrl(sourceUrl, layerOptions)
            registerImageryLayer(provider)
          } else {
            const provider = new Cesium.UrlTemplateImageryProvider({
              url: sourceUrl,
              tilingScheme: new Cesium.WebMercatorTilingScheme(),
              maximumLevel: 18,
              ...layerOptions,
            })
            registerImageryLayer(provider)
          }
          break
        }
        case 'ArcGISDynamicMapServiceLayer':
        case 'ArcGISImageMapServiceLayer': {
          const provider = await Cesium.ArcGisMapServerImageryProvider.fromUrl(sourceUrl, {
            enablePickFeatures: true,
            ...layerOptions,
          })
          registerImageryLayer(provider)
          break
        }
        case 'GeoJSONServiceLayer': {
          // Accept url or raw data in options.data
          const data = layerOptions.data || sourceUrl
          const dataSource = await Cesium.GeoJsonDataSource.load(data, layerOptions)
          await registerVectorLayer(dataSource)
          break
        }
        case 'WmsServiceLayer': {
          const base = (sourceUrl || '').split('?')[0]
          const queryParams = (sourceUrl || '').includes('?') ? new URLSearchParams((sourceUrl || '').split('?')[1]) : new URLSearchParams()
          const provider = new Cesium.WebMapServiceImageryProvider({
            url: base,
            layers: queryParams.get('layers') || layerOptions.layers,
            parameters: {
              service: 'WMS',
              version: queryParams.get('version') || layerOptions.version || '1.1.1',
              request: 'GetMap',
              format: queryParams.get('format') || layerOptions.format || 'image/png',
              transparent: true,
              cql_filter:queryParams.get('cql_filter')||'',
              ...layerOptions.extraParameters,
              ...layerOptions.parameters,
            },
            enablePickFeatures: true,
            ...layerOptions,
          })
          registerImageryLayer(provider)
          break
        }
        case 'WmtsServiceLayer':
        case 'TiandituVecLayer':
        case 'TiandituImgLayer':
        case 'TiandituCvaLayer': {
          // Try to honor tk from url or options
          const urlBase = (sourceUrl || '').split('?')[0]
          const queryParams = (sourceUrl || '').includes('?') ? new URLSearchParams((sourceUrl || '').split('?')[1]) : new URLSearchParams()
          const tk = queryParams.get('tk') || layerOptions.tk
          const wmtsUrl = tk ? `${urlBase}?tk=${tk}` : urlBase
          const provider = new Cesium.WebMapTileServiceImageryProvider({
            url: wmtsUrl,
            layer: queryParams.get('LAYER') || queryParams.get('layer') || layerOptions.layer || 'img',
            style: 'default',
            format: 'tiles',
            tileMatrixSetID: layerOptions.tileMatrixSetID || 'w',
            tilingScheme: new Cesium.WebMercatorTilingScheme(),
            maximumLevel: layerOptions.maximumLevel || 18,
            subdomains: layerOptions.subdomains || ['0', '1', '2', '3', '4', '5', '6', '7'],
            ...layerOptions,
          })
          registerImageryLayer(provider)
          break
        }
        case 'WebTileLayer': {
          const provider = new Cesium.UrlTemplateImageryProvider({
            url: sourceUrl,
            tilingScheme: new Cesium.WebMercatorTilingScheme(),
            subdomains: layerOptions.subdomains || ['0', '1', '2', '3', '4', '5', '6', '7'],
            ...layerOptions,
          })
          registerImageryLayer(provider)
          break
        }
        case 'TMSServiceLayer': { // TMS z/x/{reverseY}
          const templateUrl = typeof sourceUrl === 'string' ? sourceUrl.replace('{y}', '{reverseY}') : sourceUrl
          const providerOptions = {
            url: templateUrl,
            tilingScheme: new Cesium.WebMercatorTilingScheme(),
            maximumLevel: layerOptions.maximumLevel || layerOptions.maxZoom || 22,
            ...layerOptions,
          }
          if (layerOptions.bounds) {
            const bounds = layerOptions.bounds
            providerOptions.rectangle = Cesium.Rectangle.fromDegrees(bounds.west, bounds.south, bounds.east, bounds.north)
          }
          const provider = new Cesium.UrlTemplateImageryProvider({ ...providerOptions, url: templateUrl })
          registerImageryLayer(provider)
          break
        }
        case 'TmsServiceLayer': { // XYZ z/x/y
          const providerOptions = {
            url: sourceUrl,
            tilingScheme: new Cesium.WebMercatorTilingScheme(),
            maximumLevel: layerOptions.maximumLevel || layerOptions.maxZoom || 22,
            ...layerOptions,
          }
          if (layerOptions.bounds) {
            const bounds = layerOptions.bounds
            providerOptions.rectangle = Cesium.Rectangle.fromDegrees(bounds.west, bounds.south, bounds.east, bounds.north)
          }
          const provider = new Cesium.UrlTemplateImageryProvider(providerOptions)
          registerImageryLayer(provider)
          break
        }
        case 'Cesium3DTileService': {
          const tileset = await Cesium.Cesium3DTileset.fromUrl(sourceUrl, {
            ...layerOptions,
          })
          viewer.scene.primitives.add(tileset)
          layerRecord = {
            id: layerId,
            type: 'primitive',
            obj: tileset,
            owned: true,
            show: true,
            opacity: 1,
            meta: metadata,
          }
          store.layers[layerId] = layerRecord
          break
        }
        default:
          throw new Error('不支持的图层类型: ' + layerType)
      }

      return layerId
    },

    // 移除图层
    removeLayer(id) {
      const viewer = viewerOrThrow()
      const record = store.layers[id]
      if (!record) return false
      try {
        if (record.type === 'imagery') {
          viewer.imageryLayers.remove(record.obj, true)
          syncImageryOrderMeta(viewer)
        } else if (record.type === 'vector' || record.type === 'datasource') {
          viewer.dataSources.remove(record.obj, true)
          syncVectorOrderMeta(viewer)
        } else if (record.type === 'primitive') {
          viewer.scene.primitives.remove(record.obj)
        } else if (record.type === 'terrain') {
          if ('terrain' in viewer) viewer.terrain = new Cesium.EllipsoidTerrain()
          else viewer.scene.terrainProvider = new Cesium.EllipsoidTerrain()
        }
      } catch (e) {}
      delete store.layers[id]
      return true
    },

    // 显隐图层
    showLayer(id, visible) {
      const record = store.layers[id]
      if (!record) return
      if (record.type === 'imagery') record.obj.show = !!visible
      else if (record.type === 'vector' || record.type === 'datasource') record.obj.show = !!visible
      else if (record.type === 'primitive') record.obj.show = !!visible
      record.show = !!visible
    },

    // 设置透明度
    setOpacity(id, alpha) {
      const record = store.layers[id]
      if (!record) return
      if (record.type === 'imagery') {
        record.obj.alpha = alpha
        record.opacity = alpha
      } else {
        record.opacity = alpha /* TODO: walk entities/materials */
      }
    },

    // 调整图层顺序（上/下/置顶/置底）
    moveLayer(id, direction) {
      const viewer = viewerOrThrow()
      const record = store.layers[id]
      if (!record) return
      if (record.type === 'imagery') {
        const imageryLayers = viewer.imageryLayers
        if (direction === 'up') imageryLayers.raise(record.obj)
        else if (direction === 'down') imageryLayers.lower(record.obj)
        else if (direction === 'top') imageryLayers.raiseToTop(record.obj)
        else if (direction === 'bottom') imageryLayers.lowerToBottom(record.obj)
        syncImageryOrderMeta(viewer)
      } else if (record.type === 'vector' || record.type === 'datasource') {
        const dataSources = viewer.dataSources
        if (direction === 'up') dataSources.raise(record.obj)
        else if (direction === 'down') dataSources.lower(record.obj)
        else if (direction === 'top') dataSources.raiseToTop(record.obj)
        else if (direction === 'bottom') dataSources.lowerToBottom(record.obj)
        syncVectorOrderMeta(viewer)
      }
    },

    // 设置卷帘（左右分屏）位置
    setSplit(id, side) {
      const record = store.layers[id]
      if (!record || record.type !== 'imagery') return
      const splitDirectionMap = {
        left: SplitDirection.LEFT,
        right: SplitDirection.RIGHT,
        none: SplitDirection.NONE,
      }
      record.obj.splitDirection = splitDirectionMap[side] || SplitDirection.NONE
    },

    // 设置全局卷帘分割位置 [0,1]
    setSplitPosition(position) {
      const viewer = viewerOrThrow()
      store.imagerySplitPosition = Math.min(1, Math.max(0, position))
      try {
        viewer.scene.imagerySplitPosition = store.imagerySplitPosition
      } catch (e) {}
    },

    // 获取图层记录
    getLayer(id) {
      return store.layers[id]
    },

    // 列出所有图层记录
    listLayers() {
      return Object.values(store.layers)
    },
  }
}
