/**
 * useLayer - 图层 CRUD 操作组合式函数
 *
 * 基于 MapManager 单例中的 Map 实例，提供图层的添加、移除、显隐切换、
 * 可见性查询等响应式操作方法。
 *
 * @module map/composables/useLayer
 */

import { ref, computed, readonly, onUnmounted, type Ref, type DeepReadonly } from 'vue'
import type {
  LayerSpecification,
  CustomLayerInterface,
  FilterSpecification,
} from 'maplibre-gl'
import { MapManager } from '../MapManager'
import { useMap } from './useMap'

// ============================================================
// 类型定义
// ============================================================

/**
 * 图层操作结果
 */
export interface LayerOperationResult {
  /** 是否成功 */
  success: boolean
  /** 错误信息（失败时） */
  error?: string
}

/**
 * 图层信息
 */
export interface LayerInfo {
  /** 图层 ID */
  id: string
  /** 图层类型 */
  type: string
  /** 当前可见性 */
  visible: boolean
  /** 图层元数据（如有） */
  metadata?: Record<string, unknown>
}

/**
 * 图层可见性映射表
 *
 * key 为图层 ID，value 为 Ref<boolean> 表示该图层可见性
 */
export interface LayerVisibilityMap {
  [layerId: string]: Ref<boolean>
}

/**
 * useLayer 返回类型
 */
export interface UseLayerReturn {
  /**
   * 添加图层到地图
   *
   * @param layer - 图层配置（LayerSpecification 或 CustomLayerInterface）
   * @param beforeId - 插入到指定图层之前（可选）
   * @returns 操作结果
   */
  addLayer: (
    layer: LayerSpecification | CustomLayerInterface,
    beforeId?: string
  ) => LayerOperationResult

  /**
   * 从地图移除图层
   *
   * 同时清理该图层的可见性追踪
   *
   * @param layerId - 图层 ID
   * @returns 操作结果
   */
  removeLayer: (layerId: string) => LayerOperationResult

  /**
   * 切换图层可见性
   *
   * 如果图层当前可见则隐藏，反之则显示
   *
   * @param layerId - 图层 ID
   * @returns 操作结果
   */
  toggleLayer: (layerId: string) => LayerOperationResult

  /**
   * 设置图层可见性
   *
   * @param layerId - 图层 ID
   * @param visible - 是否可见
   * @returns 操作结果
   */
  setLayerVisibility: (layerId: string, visible: boolean) => LayerOperationResult

  /**
   * 获取图层可见性的响应式引用
   *
   * 如果图层不存在则返回始终为 false 的 ref
   *
   * @param layerId - 图层 ID
   * @returns 响应式可见性引用
   */
  getLayerVisibility: (layerId: string) => DeepReadonly<Ref<boolean>>

  /**
   * 获取所有已添加图层的 ID 列表
   *
   * @returns 图层 ID 数组
   */
  getLayerIds: () => string[]

  /**
   * 获取图层信息
   *
   * @param layerId - 图层 ID
   * @returns 图层信息，不存在则返回 null
   */
  getLayerInfo: (layerId: string) => LayerInfo | null

  /**
   * 设置图层滤镜
   *
   * @param layerId - 图层 ID
   * @param filter - 滤镜表达式，传 null 清除滤镜
   * @returns 操作结果
   */
  setLayerFilter: (
    layerId: string,
    filter: FilterSpecification | null
  ) => LayerOperationResult

  /**
   * 所有已追踪图层的可见性映射表（只读）
   */
  visibilityMap: DeepReadonly<Ref<LayerVisibilityMap>>

  /**
   * 当前图层数量
   */
  layerCount: import('vue').ComputedRef<number>
}

// ============================================================
// useLayer
// ============================================================

/**
 * 图层 CRUD 操作组合式函数
 *
 * 提供对 MapLibre GL 地图图层的添加、移除、显隐控制等操作。
 * 内部使用 useMap() 获取当前地图实例，确保操作始终针对当前地图。
 *
 * @returns 图层操作方法集合
 *
 * @example
 * ```vue
 * <script setup lang="ts">
 * import { useLayer } from '@/map/composables/useLayer'
 *
 * const { addLayer, removeLayer, toggleLayer, getLayerVisibility, layerCount } = useLayer()
 *
 * // 添加一个圆形图层
 * addLayer({
 *   id: 'points-layer',
 *   type: 'circle',
 *   source: 'my-source',
 *   paint: { 'circle-radius': 6, 'circle-color': '#ff0000' }
 * })
 *
 * // 切换可见性
 * toggleLayer('points-layer')
 *
 * // 响应式获取可见性
 * const isVisible = getLayerVisibility('points-layer')
 * </script>
 * ```
 */
export function useLayer(): UseLayerReturn {
  // ----------------------------------------------------------
  // 获取当前地图
  // ----------------------------------------------------------
  const { map } = useMap()

  // ----------------------------------------------------------
  // 内部状态
  // ----------------------------------------------------------

  /**
   * 图层可见性映射表
   *
   * 追踪所有通过本 composable 操作的图层的可见性
   */
  const visibilityMap = ref<LayerVisibilityMap>({})

  // ----------------------------------------------------------
  // 内部辅助函数
  // ----------------------------------------------------------

  /**
   * 获取当前 Map 实例，不存在则返回 null
   */
  function getMap() {
    return map.value
  }

  /**
   * 检查图层是否存在
   */
  function layerExists(layerId: string): boolean {
    const m = getMap()
    if (!m) return false
    try {
      return !!m.getLayer(layerId)
    } catch {
      return false
    }
  }

  /**
   * 同步图层可见性到内部状态
   */
  function syncLayerVisibility(layerId: string, visible: boolean): void {
    if (!visibilityMap.value[layerId]) {
      visibilityMap.value[layerId] = ref(visible)
    } else {
      visibilityMap.value[layerId].value = visible
    }
  }

  // ----------------------------------------------------------
  // 公开方法
  // ----------------------------------------------------------

  /**
   * 添加图层到地图
   */
  function addLayer(
    layer: LayerSpecification | CustomLayerInterface,
    beforeId?: string
  ): LayerOperationResult {
    const m = getMap()
    if (!m) {
      return { success: false, error: '地图实例不存在，请先创建地图' }
    }

    try {
      // 检查图层是否已存在
      if (m.getLayer(layer.id)) {
        return { success: false, error: `图层 "${layer.id}" 已存在` }
      }

      // 检查 beforeId 是否存在
      if (beforeId && !m.getLayer(beforeId)) {
        return {
          success: false,
          error: `参考图层 "${beforeId}" 不存在`,
        }
      }

      m.addLayer(layer, beforeId)

      // 追踪可见性
      const visibility = 'layout' in layer && layer.layout && 'visibility' in layer.layout
        ? (layer.layout as { visibility?: string }).visibility !== 'none'
        : true
      syncLayerVisibility(layer.id, visibility)

      // 触发响应式更新
      visibilityMap.value = { ...visibilityMap.value }

      return { success: true }
    } catch (err) {
      return {
        success: false,
        error: err instanceof Error ? err.message : '添加图层失败',
      }
    }
  }

  /**
   * 从地图移除图层
   */
  function removeLayer(layerId: string): LayerOperationResult {
    const m = getMap()
    if (!m) {
      return { success: false, error: '地图实例不存在' }
    }

    try {
      if (!m.getLayer(layerId)) {
        return { success: false, error: `图层 "${layerId}" 不存在` }
      }

      m.removeLayer(layerId)

      // 清理可见性追踪
      if (visibilityMap.value[layerId]) {
        const newMap = { ...visibilityMap.value }
        delete newMap[layerId]
        visibilityMap.value = newMap
      }

      return { success: true }
    } catch (err) {
      return {
        success: false,
        error: err instanceof Error ? err.message : '移除图层失败',
      }
    }
  }

  /**
   * 切换图层可见性
   */
  function toggleLayer(layerId: string): LayerOperationResult {
    if (!layerExists(layerId)) {
      return { success: false, error: `图层 "${layerId}" 不存在` }
    }

    const currentVisibility = visibilityMap.value[layerId]?.value ?? true
    return setLayerVisibility(layerId, !currentVisibility)
  }

  /**
   * 设置图层可见性
   */
  function setLayerVisibility(layerId: string, visible: boolean): LayerOperationResult {
    const m = getMap()
    if (!m) {
      return { success: false, error: '地图实例不存在' }
    }

    try {
      if (!m.getLayer(layerId)) {
        return { success: false, error: `图层 "${layerId}" 不存在` }
      }

      const visibility = visible ? 'visible' : 'none'
      m.setLayoutProperty(layerId, 'visibility', visibility)

      syncLayerVisibility(layerId, visible)

      return { success: true }
    } catch (err) {
      return {
        success: false,
        error: err instanceof Error ? err.message : '设置图层可见性失败',
      }
    }
  }

  /**
   * 获取图层可见性的响应式引用
   */
  function getLayerVisibility(layerId: string): DeepReadonly<Ref<boolean>> {
    if (!visibilityMap.value[layerId]) {
      // 惰性初始化：直接从地图读取当前状态
      const m = getMap()
      let visible = false
      if (m && m.getLayer(layerId)) {
        try {
          const v = m.getLayoutProperty(layerId, 'visibility')
          visible = v !== 'none'
        } catch {
          visible = true
        }
      }
      visibilityMap.value[layerId] = ref(visible)
      visibilityMap.value = { ...visibilityMap.value }
    }

    return readonly(visibilityMap.value[layerId])
  }

  /**
   * 获取所有已添加图层的 ID 列表
   */
  function getLayerIds(): string[] {
    const m = getMap()
    if (!m) return []
    return m.getStyle()?.layers?.map((l) => l.id) ?? []
  }

  /**
   * 获取图层信息
   */
  function getLayerInfo(layerId: string): LayerInfo | null {
    const m = getMap()
    if (!m) return null

    try {
      const layer = m.getLayer(layerId)
      if (!layer) return null

      const visibility = visibilityMap.value[layerId]?.value ?? true

      return {
        id: layer.id,
        type: layer.type,
        visible: visibility,
        metadata: (layer as LayerSpecification).metadata as Record<string, unknown> | undefined,
      }
    } catch {
      return null
    }
  }

  /**
   * 设置图层滤镜
   */
  function setLayerFilter(
    layerId: string,
    filter: FilterSpecification | null
  ): LayerOperationResult {
    const m = getMap()
    if (!m) {
      return { success: false, error: '地图实例不存在' }
    }

    try {
      if (!m.getLayer(layerId)) {
        return { success: false, error: `图层 "${layerId}" 不存在` }
      }

      if (filter === null) {
        // 清除滤镜
        m.setFilter(layerId, null as unknown as FilterSpecification)
      } else {
        m.setFilter(layerId, filter)
      }

      return { success: true }
    } catch (err) {
      return {
        success: false,
        error: err instanceof Error ? err.message : '设置图层滤镜失败',
      }
    }
  }

  // ----------------------------------------------------------
  // 计算属性
  // ----------------------------------------------------------

  /** 当前图层数量 */
  const layerCount = computed(() => {
    const m = getMap()
    if (!m) return 0
    return m.getStyle()?.layers?.length ?? 0
  })

  // ----------------------------------------------------------
  // 组件卸载时清理
  // ----------------------------------------------------------
  onUnmounted(() => {
    visibilityMap.value = {}
  })

  // ----------------------------------------------------------
  // 返回
  // ----------------------------------------------------------
  return {
    addLayer,
    removeLayer,
    toggleLayer,
    setLayerVisibility,
    getLayerVisibility,
    getLayerIds,
    getLayerInfo,
    setLayerFilter,
    visibilityMap: readonly(visibilityMap),
    layerCount,
  }
}
