/**
 * 地图服务层
 *
 * 设计模式：外观模式（Facade Pattern） + 单例模式（Singleton Pattern）
 *
 * 作用：
 * 1. 为业务层提供统一的地图操作接口，完全屏蔽底层地图内核差异
 * 2. 通过单例模式确保整个应用使用同一个地图实例，保持状态一致性
 * 3. 简化业务层调用，无需关心适配器创建和地图引擎切换
 * 4. 支持运行时动态切换地图引擎，对用户无感
 *
 * 使用方式：
 * - 在 Vue 组件中直接导入 mapService 使用
 * - 所有方法都是异步的，返回 Promise
 *
 * @module mapService
 */

import { createMapAdapter } from './mapKernelFactory'

/**
 * 地图服务类
 *
 * 封装地图适配器，为业务层提供统一的地图操作接口
 *
 * @class MapService
 */
class MapService {
  /**
   * 构造函数
   *
   * 初始化时根据全局配置创建对应的地图适配器实例
   */
  constructor () {
    /**
     * 地图适配器实例
     * 根据 mapConfig.js 中的 MAP_ENGINE 配置自动选择对应的适配器
     * 'AMAP' | 'OPENLAYERS'
     * @type {MapAdapter}
     */
    this.engine = 'AMAP'
    this.adapter = createMapAdapter(this.engine)

    /**
     * 地图容器引用
     * 用于切换引擎时重新初始化地图
     *
     * @type {HTMLElement|null}
     */
    this.container = null

    /**
     * 地图初始化配置
     * 用于切换引擎时恢复地图状态
     *
     * @type {object|null}
     */
    this.initOptions = null

    /**
     * 状态变更回调函数
     * 用于通知外部地图加载状态变化
     *
     * @type {Function|null}
     */
    this.onLoadingChange = null

    /**
     * 视图变更回调函数（中心点/缩放）
     * @type {Function|null}
     */
    this.onViewChange = null

    /**
     * WMS点击查询是否启用
     * @type {boolean}
     */
    this.wmsClickEnabled = false

    /**
     * 通用地图点击是否启用
     */
    this.mapClickEnabled = false
  }

  /**
   * 初始化地图
   *
   * @param {string|HTMLElement} container - 地图容器
   * @param {object} options - 初始化配置 AMAP |  OPENLAYERS
   * @returns {Promise} 地图实例
   */
  async initMap (container, options) {
    // 保存容器和配置，用于切换引擎时重新初始化
    this.container = typeof container === 'string'
      ? document.querySelector(container)
      : container
    this.initOptions = options

    // 显示加载提示
    this.setLoading(true)

    try {
      const result = await this.adapter.initMap(container, options)
      if (this.adapter.bindViewChange) {
        this.adapter.bindViewChange((center) => {
          if (this.onViewChange) {
            this.onViewChange(center)
          }
        })
      }
      this.setLoading(false)
      return result
    } catch (error) {
      this.setLoading(false)
      throw error
    }
  }

  /**
   * 检查地图服务是否处于就绪状态
   * @returns {boolean}
   */
  isReady () {
    return !!(
      this.container && // 容器已挂载
      this.adapter // 适配器已创建
    )
  }

  /**
   * 设置加载状态回调
   *
   * @param {Function} callback - 回调函数，参数为 (loading: boolean)
   */
  setLoadingCallback (callback) {
    this.onLoadingChange = callback
  }

  /**
   * 设置视图变更回调（中心点/缩放等）
   * @param {Function} callback
   */
  setViewChangeCallback (callback) {
    this.onViewChange = callback
  }

  /**
   * 初始化WMS点击事件处理器
   *
   * 该函数用于初始化WMS（Web Map Service）图层的点击事件处理功能。
   * 它会检查当前实例是否具有适配器对象，并且该适配器是否实现了initWmsClickHandler方法，
   * 如果条件满足，则调用适配器的对应方法来完成具体的初始化操作。
   */
  initWmsClickHandler () {
    // 检查适配器是否存在且具有initWmsClickHandler方法，避免调用不存在的方法导致错误
    if (this.adapter && this.adapter.initWmsClickHandler) {
      this.adapter.initWmsClickHandler()
    }
  }

  /**
   * 获取WMS图层的GetFeatureInfo URL
   * @param {string} layerId - 图层ID
   * @param {Array<number>} coordinate - 点击坐标 [lng, lat]
   * @returns {string|null} GetFeatureInfo URL
   */
  getWmsFeatureInfoUrl (layerId, coordinate) {
    if (this.adapter && this.adapter.getWmsFeatureInfoUrl) {
      return this.adapter.getWmsFeatureInfoUrl(layerId, coordinate)
    }
    return null
  }

  /**
   * 设置WMS点击查询回调
   * @param {Function} callback - 回调函数，参数为 (coordinate: Array<number>)
   */
  setWmsClickCallback (callback) {
    this.onWmsClick = callback
    if (this.adapter && this.adapter.setWmsClickCallback) {
      this.adapter.setWmsClickCallback(callback)
    }
  }

  /**
   * 设置WMS点击查询启用状态
   * @param {boolean} enabled
   */
  setWmsClickEnabled (enabled) {
    this.wmsClickEnabled = enabled
    if (this.adapter && this.adapter.setWmsClickEnabled) {
      this.adapter.setWmsClickEnabled(enabled)
    }
  }

  /**
   * 设置WMS鼠标悬停样式启用状态
   * 当鼠标悬停在 WMS 图层上时，改变鼠标样式为 pointer
   * @param {boolean} enabled
   */
  setWmsHoverEnabled (enabled) {
    if (this.adapter && this.adapter.setWmsHoverEnabled) {
      this.adapter.setWmsHoverEnabled(enabled)
    }
  }

  /**
   * 设置通用地图点击回调
   */
  setMapClickCallback (callback) {
    if (this.adapter && this.adapter.setMapClickCallback) {
      this.adapter.setMapClickCallback(callback)
    }
  }

  /**
   * 设置通用地图点击启用状态
   */
  setMapClickEnabled (enabled) {
    this.mapClickEnabled = enabled
    if (this.adapter && this.adapter.setMapClickEnabled) {
      this.adapter.setMapClickEnabled(enabled)
    }
  }

  /**
   * 设置加载状态
   *
   * @param {boolean} loading - 是否加载中
   * @private
   */
  setLoading (loading) {
    if (this.onLoadingChange) {
      this.onLoadingChange(loading)
    }
  }

  /**
   * 批量添加标记点
   *
   * @param {Function} getDataFn - 获取标记点数据的函数，返回 Promise<Array<object>>
   * @param {object} options - 组配置选项
   * @param {string} options.groupId - 组数据唯一标识
   * @param {string} options.groupName - 组数据名称
   * @param {boolean} [options.visible=true] - 默认是否显示，默认 true
   * @returns {Promise<Array>} 标记点实例数组
   */
  /**
   * 批量添加标记点
   *
   * @param {Function} getDataFn 获取标记点数据的函数，返回 Promise<Array<object>>
   * @param {object} options 组配置选项 { groupId, groupName, visible? }
   * @param {Function} [onClick] 点位点击回调 (payload) => void
   * @returns {Promise<Array>} 标记点实例数组
   */
  addMarker (getDataFn, options = {}, onClick) {
    return this.adapter.addMarker(getDataFn, options, onClick)
  }

  /**
   * 添加热力图
   *
   * @param {Function} getDataFn 获取热力图数据的函数，返回 Promise<Array<object>>
   * @param {object} options 组配置选项 { groupId, groupName, visible? }
   * @returns {Promise} 热力图实例
   */
  addHeatmap (getDataFn, options = {}) {
    return this.adapter.addHeatmap(getDataFn, options)
  }

  /**
   * 批量绘制多边形
   *
   * @param {Function} getDataFn - 获取多边形数据的函数，返回 Promise<Array<object>>
   * @param {object} options - 组配置选项
   * @param {string} options.groupId - 组数据唯一标识
   * @param {string} options.groupName - 组数据名称
   * @param {boolean} [options.visible=true] - 默认是否显示，默认 true
   * @returns {Promise<Array>} 多边形实例数组
   */
  drawPolygon (getDataFn, options = {}) {
    return this.adapter.drawPolygon(getDataFn, options)
  }

  /**
   * 添加单个 WMS 图层
   *
   * @param {object} layerOptions - WMS 图层配置对象
   * @param {string} groupId - 组数据唯一标识
   * @param {string} groupName - 组数据名称
   * @param {string} [groupType='wms'] - 组类型标识
   * @returns {Promise<Array>} 图层实例数组（单元素）
   */
  addWmsLayer (layerOptions, groupId, groupName, groupType = 'wms') {
    return this.adapter.addWmsLayer(layerOptions, groupId, groupName, groupType)
  }

  /**
   * 批量绘制折线
   * @param {Function} getDataFn 获取数据函数
   * @param {object} options 组配置
   */
  addPolyline (getDataFn, options = {}) {
    return this.adapter.addPolyline(getDataFn, options)
  }

  /**
   * 开启组闪烁
   * @param {string} groupId 组 ID
   * @param {number} interval 间隔
   */
  startGroupBlink (groupId, interval = 600) {
    return this.adapter.startGroupBlink(groupId, interval)
  }

  /**
   * 停止组闪烁
   * @param {string} groupId 组 ID
   */
  stopGroupBlink (groupId) {
    return this.adapter.stopGroupBlink(groupId)
  }

  /**
   * 开始自由画线
   * @param {Function} onComplete 完成回调
   */
  startLineDraw (onComplete) {
    return this.adapter.startLineDraw(onComplete)
  }

  /**
   * 结束自由画线
   */
  stopLineDraw () {
    return this.adapter.stopLineDraw()
  }

  /**
   * 开始单条直线绘制（目前仅用于切面分析）
   * 只能绘制一条直线（两个点），绘制完成后自动结束交互
   * @param {Function} onComplete 完成回调，参数为坐标数组 [[lng, lat], [lng, lat]]（4326坐标）
   */
  startStraightLineDraw (onComplete) {
    return this.adapter.startStraightLineDraw(onComplete)
  }

  /**
   * 停止单条直线绘制
   */
  stopStraightLineDraw () {
    if (this.adapter && this.adapter.stopStraightLineDraw) {
      return this.adapter.stopStraightLineDraw()
    }
  }

  /**
   * 清理图层
   *
   * @param {string} [layerId] - 图层 ID，不传则清理所有
   * @returns {Promise} 清理结果
   */
  clearLayer (layerId) {
    return this.adapter.clearLayer(layerId)
  }

  /**
   * 切换底图
   *
   * @param {string} mapType - 底图类型
   * @returns {Promise|void} 切换结果
   */
  switchBaseMap (mapType) {
    return this.adapter.switchBaseMap(mapType)
  }

  /**
   * 设置组数据显隐状态
   *
   * @param {string} groupId - 组数据唯一标识
   * @param {boolean} visible - 是否显示
   * @returns {Promise<void>}
   */
  setGroupVisible (groupId, visible) {
    return this.adapter.setGroupVisible(groupId, visible)
  }

  /**
   * 获取所有组数据信息
   *
   * @returns {Promise<Array<object>>} 组数据信息数组
   */
  getGroups () {
    return this.adapter.getGroups()
  }

  /**
   * 获取指定组数据信息
   *
   * @param {string} groupId - 组数据唯一标识
   * @returns {Promise<object>} 组数据信息
   */
  getGroupById (groupId) {
    return this.adapter.getGroupById(groupId)
  }

  /**
   * 根据 type 获取图层组，如果不传 type 则返回所有组
   * @param {string} [type] - 可选，要过滤的图层类型 (如 'marker', 'polygon')
   * @returns {Array<Object>} 过滤后的图层组数组
   */
  getGroupsByType (type) {
    return this.adapter.getGroupsByType(type)
  }

  /**
   * 将图层组按 groupType 分类，或获取指定分类的图层组
   * @param {string} [specificGroupType] - 可选，指定要获取的 groupType
   * @returns {Array<Object>|Array<{groupType: string, groups: Array<Object>}>}
   *          如果传入了 specificGroupType，返回该分类的组数组；
   *          否则，返回所有分类的对象数组。
   */
  getGroupsByGroupType (specificGroupType) {
    return this.adapter.getGroupsByGroupType(specificGroupType)
  }

  /**
   * 切换地图引擎
   *
   * 实现运行时动态切换地图引擎，对用户无感：
   * 1. 保存当前地图状态（中心点、缩放级别、组数据等）
   * 2. 销毁当前地图实例
   * 3. 切换配置中的引擎类型
   * 4. 创建新的适配器实例
   * 5. 重新初始化地图并恢复状态
   *
   * @param {string} engine - 目标引擎：'AMAP' | 'OPENLAYERS'
   * @returns {Promise<void>}
   */
  async switchEngine (engine) {
    if (!this.container) {
      throw new Error('Map not initialized. Call initMap first.')
    }

    if (engine === this.engine) {
      console.warn(`Already using ${engine} engine`)
      return
    }

    // 显示加载提示
    this.setLoading(true)

    try {
      // 1. 保存当前地图状态
      const mapState = this.adapter.getMapState ? this.adapter.getMapState() : null

      // 2. 销毁当前地图实例
      if (this.adapter.destroy) {
        this.adapter.destroy()
      }

      // 3. 切换配置中的引擎类型
      this.engine = engine

      // 4. 创建新的适配器实例
      this.adapter = createMapAdapter(this.engine)

      // 5. 重新初始化地图
      const initOptions = { ...this.initOptions }
      if (mapState && mapState.center) {
        initOptions.center = mapState.center
      }
      if (mapState && mapState.zoom !== null) {
        initOptions.zoom = mapState.zoom
      }
      if (mapState && mapState.baseMapType) {
        initOptions.baseType = mapState.baseMapType
      }

      await this.adapter.initMap(this.container, initOptions)
      if (this.adapter.bindViewChange) {
        this.adapter.bindViewChange((center) => {
          if (this.onViewChange) {
            this.onViewChange(center)
          }
        })
      }

      // 6. 恢复组数据（需要重新添加）
      if (mapState && mapState.groups) {
        // 这里可以根据需要恢复组数据
        // 由于不同引擎的实现不同，可能需要重新调用 addMarker/drawPolygon/addWmsLayer
        // 暂时只恢复地图视图状态，组数据需要业务层重新添加
        console.log('Map engine switched. Groups need to be re-added by business layer.')
      }

      this.setLoading(false)
    } catch (error) {
      this.setLoading(false)
      console.error('Failed to switch map engine:', error)
      throw error
    }
  }

  /**
   * 获取当前地图引擎
   *
   * @returns {string} 当前地图引擎：'AMAP' | 'OPENLAYERS'
   */
  getCurrentEngine () {
    return this.engine
  }

  /**
   * 地图放大
   */
  zoomIn () {
    return this.adapter.zoomIn()
  }

  /**
   * 地图缩小
   */
  zoomOut () {
    return this.adapter.zoomOut()
  }

  /**
   * 设置地图视图
   * @param {number} zoom - 缩放级别
   * @param center
   */
  fitView (zoom = null, center = null) {
    return this.adapter.fitView(zoom, center)
  }

  /**
   * 启用框选放大功能
   * @param {Function} onComplete - 框选完成回调，参数为 { bounds, center }
   */
  enableZoomToBox (onComplete) {
    return this.adapter.enableZoomToBox(onComplete)
  }

  /**
   * 禁用框选放大功能
   */
  disableZoomToBox () {
    return this.adapter.disableZoomToBox()
  }

  /**
   * 启动距离测量
   * @param {Function} onResultChange - (results) => void
   */
  startDistanceMeasure (onResultChange) {
    return this.adapter.startDistanceMeasure(onResultChange)
  }

  /**
   * 清空测量结果
   */
  clearMeasureResults () {
    return this.adapter.clearMeasureResults()
  }

  /**
   * 启动面积测量
   */
  startAreaMeasure () {
    return this.adapter.startAreaMeasure()
  }

  /**
   * 切换地图 2D / 3D 视图
   */
  setMapViewMode () {
    return this.adapter.setMapViewMode()
  }

  /**
   * 获取当前地图视图模式
   */
  getMapViewMode () {
    return this.adapter.getMapViewMode()
  }

  startRectangleSelect (onComplete) {
    return this.adapter.startRectangleSelect(onComplete)
  }

  startCircleSelect (onComplete) {
    return this.adapter.startCircleSelect(onComplete)
  }

  startPolygonSelect (onComplete) {
    return this.adapter.startPolygonSelect(onComplete)
  }

  stopSelectInteraction () {
    return this.adapter.stopSelectInteraction()
  }

  /**
   * 清理框选结果（不再按 type 区分，直接清除所有框选绘制）
   */
  clearSelectResults () {
    return this.adapter.clearSelectResults()
  }

  /**
   * 根据边界框设置地图视图
   * @param {Array<Array<number>>} bounds - 边界框 [[minLng, minLat], [maxLng, maxLat]]
   * @param {Array<number>} center - 中心点 [lng, lat]
   */
  zoomToBounds (bounds, center) {
    return this.adapter.zoomToBounds(bounds, center)
  }

  /**
   * 当前定位
   * 获取用户当前位置并定位到地图中心
   * @returns {Promise<{longitude: number, latitude: number}>} 返回定位坐标 {longitude, latitude}
   */
  locateCurrent () {
    return this.adapter.locateCurrent()
  }

  /**
   * 设置当前引擎（初始化前调用）
   * @param {string} engine
   */
  setEngine (engine) {
    if (!engine || engine === this.engine) return
    this.engine = engine
    this.adapter = createMapAdapter(this.engine)
  }

  /**
   * 刷新当前显示的WMS图层（强制刷新缓存）
   * 只更新时间戳参数，不移除图层
   */
  refreshWmsLayers (key) {
    this.adapter.refreshWmsLayers(key)
  }

  /**
   * 打开信息窗口
   * @param {Array<number>} coordinate - 坐标 [lng, lat]
   * @param {string|HTMLElement} content - 窗口内容（HTML字符串或DOM元素）
   * @param {object} [options] - 可选配置
   * @param {number} [options.width] - 窗口宽度（像素）
   * @param {number} [options.height] - 窗口高度（像素）
   * @param {boolean} [options.closeOnClick] - 点击地图是否关闭窗口
   * @returns {Promise<void>}
   */
  openInfoWindow (coordinate, content, options = {}) {
    return this.adapter.openInfoWindow(coordinate, content, options)
  }

  /**
   * 关闭信息窗口
   * @returns {Promise<void>}
   */
  closeInfoWindow () {
    return this.adapter.closeInfoWindow()
  }

  /**
   * 添加轨迹
   * @param {Array<{key: string, path: Array<{x: number, y: number}>}>} segments - 轨迹段数组
   * @param {object} config - 轨迹配置
   * @returns {Promise<void>}
   */
  addTrajectory (segments, config = {}) {
    return this.adapter.addTrajectory(segments, config)
  }

  /**
   * 开始播放轨迹
   * @returns {Promise<void>}
   */
  startTrajectory () {
    return this.adapter.startTrajectory()
  }

  /**
   * 重新播放轨迹
   * @returns {Promise<void>}
   */
  replayTrajectory () {
    return this.adapter.replayTrajectory()
  }

  /**
   * 暂停播放轨迹
   * @returns {Promise<void>}
   */
  pauseTrajectory () {
    return this.adapter.pauseTrajectory()
  }

  /**
   * 继续播放轨迹
   * @returns {Promise<void>}
   */
  resumeTrajectory () {
    return this.adapter.resumeTrajectory()
  }

  /**
   * 清除轨迹
   * @returns {Promise<void>}
   */
  clearTrajectory () {
    return this.adapter.clearTrajectory()
  }

  /**
   * 获取轨迹播放状态
   * @param {string} [key] - 可选，获取指定字段
   * @returns {object|*} 完整状态对象或指定字段值
   */
  getTrajectoryState (key) {
    return this.adapter.getTrajectoryState(key)
  }

  /**
   * 设置轨迹播放状态
   * @param {object|string} stateOrKey - 完整状态对象或字段名
   * @param {*} value - 字段值（当第一个参数为字段名时）
   * @returns {Promise<void>}
   */
  setTrajectoryState (stateOrKey, value) {
    return this.adapter.setTrajectoryState(stateOrKey, value)
  }
}

/**
 * 地图服务单例实例
 *
 * 导出单例确保：
 * 1. 整个应用使用同一个地图服务实例
 * 2. 地图状态在应用内保持一致
 * 3. 避免重复创建适配器实例，节省资源
 *
 * @type {MapService}
 */
const mapService = new MapService()
export default mapService
