<template>
  <div class="layer-directory-control">
    <el-tooltip content="图层目录" placement="right">
      <el-button
        class="layer-directory-control__toggle"
        type="primary"
        @click="togglePanel"
      >
        <MapIcon icon-class="GisLayers" />
      </el-button>
    </el-tooltip>
    <transition name="layer-directory-fade">
      <div
        v-if="panelVisible"
        class="layer-directory-control__panel"
      >
        <el-card class="layer-directory-control__card" shadow="always">
          <div class="layer-directory-control__card-header">
            <el-tabs v-model="activeTab" stretch>
              <el-tab-pane label="目录视图" name="catalog" />
              <el-tab-pane label="图层视图" name="loaded" />
            </el-tabs>
            <el-button
              type="text"
              :icon="Close"
              class="layer-directory-control__close"
              @click="panelVisible = false"
            />
          </div>
          <div v-if="activeTab === 'catalog'" class="layer-directory-control__body">
            <el-input
              v-model="filterText"
              class="layer-directory-control__search"
              clearable
              :prefix-icon="Search"
              placeholder="搜索图层"
            />
            <el-scrollbar class="layer-directory-control__scroll">
              <el-tree
                ref="treeRef"
                :data="treeData"
                :props="treeProps"
                node-key="id"
                show-checkbox
                highlight-current
                :expand-on-click-node="false"
                :default-expanded-keys="defaultExpandedKeys"
                @check-change="handleTreeCheckChange"
                :filter-node-method="filterTreeNode"
              />
            </el-scrollbar>
          </div>
          <div v-else class="layer-directory-control__body">
            <el-scrollbar class="layer-directory-control__scroll">
              <div
                v-if="layerItems.length"
                class="layer-directory-control__layer-list"
              >
                <div
                  v-for="item in layerItems"
                  :key="item.id"
                  class="layer-directory-control__layer-item"
                >
                  <div class="layer-directory-control__layer-main">
                    <el-icon class="layer-directory-control__layer-icon">
                      <CollectionTag v-if="item.type === 'imagery'" />
                      <DataAnalysis v-else-if="item.type === 'vector' || item.type === 'datasource'" />
                      <Operation v-else />
                    </el-icon>
                    <span class="layer-directory-control__layer-title">
                      {{ item.meta?.title || item.id }}
                    </span>
                  </div>
                  <div class="layer-directory-control__layer-actions">
                    <el-button-group>
                      <el-button
                        size="small"
                        :icon="ArrowUp"
                        @click="moveLayer(item.id, 'up')"
                        :disabled="!layerService"
                      />
                      <el-button
                        size="small"
                        :icon="ArrowDown"
                        @click="moveLayer(item.id, 'down')"
                        :disabled="!layerService"
                      />
                    </el-button-group>
                    <el-button
                      size="small"
                      type="text"
                      @click="toggleLayerVisibility(item)"
                    >
                      <el-icon>
                        <View v-if="!item.show" />
                        <Hide v-else />
                      </el-icon>
                      <span class="layer-directory-control__layer-action-text">
                        {{ item.show ? '隐藏' : '显示' }}
                      </span>
                    </el-button>
                  </div>
                </div>
              </div>
              <el-empty v-else description="暂无已加载图层" />
            </el-scrollbar>
          </div>
        </el-card>
      </div>
    </transition>
  </div>
</template>

<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { ElMessage } from 'element-plus'
import { ArrowDown, ArrowUp, Close, DataAnalysis, Hide, Operation, Search, View, CollectionTag } from '@element-plus/icons-vue'
import MapIcon from '@/map/shared/SvgIcon/index.vue'
import useMapStore from '@/map/stores/mapStore'
import layerCatalog from '@/map/data/layerMap.json'
import { DEFAULT_VECTOR_LAYER_ID } from '@/map/utils/utils'

const mapStore = useMapStore()
const { layers: layerTable } = storeToRefs(mapStore)

const panelVisible = ref(false)
const activeTab = ref('catalog')
const filterText = ref('')
const treeRef = ref(null)
const layerService = shallowRef(null)
let detachReadyListener = null
let syncingTree = false

const treeProps = {
  label: 'label',
  children: 'children',
  disabled: 'disableCheckbox',
}

const { treeData, defaultExpandedKeys, serviceNodeMap } = buildCatalogTree(layerCatalog)

const loadedCatalogKeys = computed(() => {
  const keys = Object.keys(layerTable.value || {})
  const serviceKeys = keys.filter((key) => key.startsWith('catalog:'))
  
  // 同时计算应该选中的分组节点
  const groupKeys = []
  treeData.forEach(node => {
    checkGroupNodeState(node, serviceKeys, groupKeys)
  })
  
  return [...serviceKeys, ...groupKeys]
})

/**
 * @description 检查分组节点状态，如果所有子服务都已加载则添加到选中列表
 */
function checkGroupNodeState(node, loadedServiceKeys, groupKeys) {
  if (node.nodeType === 'group' && node.children) {
    const serviceNodes = getAllServiceNodesFromGroup(node)
    const allServicesLoaded = serviceNodes.length > 0 && 
      serviceNodes.every(serviceNode => loadedServiceKeys.includes(serviceNode.id))
    
    if (allServicesLoaded) {
      groupKeys.push(node.id)
    }
    
    // 递归检查子分组
    node.children.forEach(child => {
      if (child.nodeType === 'group') {
        checkGroupNodeState(child, loadedServiceKeys, groupKeys)
      }
    })
  }
}

const layerItems = computed(() => {
  const items = Object.values(layerTable.value || {})
    .filter((item) => item && item.meta?.isBaseMap !== true && item.id !== DEFAULT_VECTOR_LAYER_ID)
  const getOrder = (record) => {
    if (!record) return 0
    if (record.type === 'imagery') return (record.meta?.zIndex ?? 0) + 1000
    if (record.type === 'vector' || record.type === 'datasource') return (record.meta?.vectorOrder ?? 0) + 500
    return record.meta?.zIndex ?? 0
  }
  return items.sort((a, b) => getOrder(b) - getOrder(a))
})

function togglePanel() {
  panelVisible.value = !panelVisible.value
}

function resolveLayerService() {
  try {
    layerService.value = mapStore.services().layer
  } catch (err) {
    layerService.value = null
  }
}

onMounted(() => {
  resolveLayerService()
  detachReadyListener = mapStore.onReady(() => {
    resolveLayerService()
  })
  nextTick(() => {
    syncTreeCheckedKeys()
  })
})

onBeforeUnmount(() => {
  if (typeof detachReadyListener === 'function') {
    detachReadyListener()
  }
})

watch(
  () => mapStore.ready,
  (ready) => {
    if (ready) resolveLayerService()
    else layerService.value = null
  }
)

watch(filterText, (value) => {
  if (!treeRef.value) return
  treeRef.value.filter(value)
})

watch(loadedCatalogKeys, () => {
  syncTreeCheckedKeys()
})

function syncTreeCheckedKeys() {
  if (!treeRef.value) return
  syncingTree = true
  treeRef.value.setCheckedKeys(loadedCatalogKeys.value, true)
  nextTick(() => {
    syncingTree = false
  })
}

function filterTreeNode(value, data) {
  if (!value) return true
  const keyword = String(value).trim().toLowerCase()
  return data.label.toLowerCase().includes(keyword)
}

/**
 * @description 递归获取分组下的所有服务节点
 */
function getAllServiceNodesFromGroup(groupNode) {
  const serviceNodes = []
  
  function collectServiceNodes(node) {
    if (node.nodeType === 'service') {
      serviceNodes.push(node)
    } else if (node.nodeType === 'group' && node.children) {
      node.children.forEach(child => collectServiceNodes(child))
    }
  }
  
  if (groupNode.children) {
    groupNode.children.forEach(child => collectServiceNodes(child))
  }
  
  return serviceNodes
}

async function handleTreeCheckChange(data, checked) {
  if (syncingTree) return
  if (!data) return
  if (!layerService.value) {
    treeRef.value.setChecked(data.id, false, true)
    ElMessage.warning('地图尚未就绪，稍后再试')
    return
  }

  try {
    if (data.nodeType === 'service') {
      // 处理服务节点
      const nodeSpec = serviceNodeMap.get(data.id)
      if (!nodeSpec) return
      
      if (checked) {
        await layerService.value.addLayer(createLayerSpec(nodeSpec))
      } else {
        await layerService.value.removeLayer(data.id)
      }
    } else if (data.nodeType === 'group') {
      // 处理分组节点 - 递归处理所有子服务节点
      const serviceNodes = getAllServiceNodesFromGroup(data)
      
      if (checked) {
        // 依次加载所有子服务
        for (const serviceNode of serviceNodes) {
          const nodeSpec = serviceNodeMap.get(serviceNode.id)
          if (nodeSpec) {
            try {
              await layerService.value.addLayer(createLayerSpec(nodeSpec))
            } catch (err) {
              console.error(`图层 ${serviceNode.label} 加载失败`, err)
              // 继续加载其他图层，不中断整个过程
            }
          }
        }
        ElMessage.success(`已加载 ${data.label} 分组下的 ${serviceNodes.length} 个图层`)
      } else {
        // 移除所有子服务
        for (const serviceNode of serviceNodes) {
          try {
            await layerService.value.removeLayer(serviceNode.id)
          } catch (err) {
            console.error(`图层 ${serviceNode.label} 移除失败`, err)
            // 继续移除其他图层
          }
        }
        ElMessage.success(`已移除 ${data.label} 分组下的 ${serviceNodes.length} 个图层`)
      }
    }
  } catch (err) {
    console.error('图层操作失败', err)
    ElMessage.error('图层操作失败：' + (err?.message || '未知错误'))
    syncingTree = true
    treeRef.value.setChecked(data.id, !checked, true)
    nextTick(() => {
      syncingTree = false
    })
  }
}

function moveLayer(id, direction) {
  if (!layerService.value) return
  try {
    layerService.value.moveLayer(id, direction)
  } catch (err) {
    console.error('图层顺序调整失败', err)
    ElMessage.error('图层顺序调整失败')
  }
}

function toggleLayerVisibility(record) {
  if (!layerService.value || !record) return
  try {
    layerService.value.showLayer(record.id, !record.show)
  } catch (err) {
    console.error('图层显隐失败', err)
    ElMessage.error('图层显隐失败')
  }
}

/**
 * @description 构造图层加载参数
 */
function createLayerSpec(nodeSpec) {
  const url = nodeSpec.url
  const serviceTypeName = nodeSpec.serviceType
  const options = buildLayerOptions(nodeSpec)
  const layerType = resolveNodeLayerType(serviceTypeName, url)
  return {
    id: nodeSpec.id,
    type: layerType,
    url,
    options: {
      visible: true,
      ...options,
    },
    meta: {
      title: nodeSpec.label,
      sourceRid: nodeSpec.rid,
      sourceType: 'catalog',
      groupName: nodeSpec.parentName,
      zIndex: typeof nodeSpec.sortValue === 'number' ? nodeSpec.sortValue : Number(nodeSpec.sortValue) || undefined,
    },
  }
}

/**
 * @description 推断节点对应的图层类型
 */
function resolveNodeLayerType(serviceTypeName, url) {
  if (serviceTypeName) return serviceTypeName
  if (!url) return ''
  if (/(wmts|TILEMATRIXSET)/i.test(url)) return 'WmtsServiceLayer'
  if (/(\{z\}|\{x\}|\{y\})/i.test(url)) return 'WebTileLayer'
  if (/geojson/i.test(url)) return 'GeoJSONServiceLayer'
  return 'WebTileLayer'
}

/**
 * @description 构造附加的图层加载配置
 */
function buildLayerOptions(nodeSpec) {
  const options = {}
  const { rawAttribute } = nodeSpec
  const expandOptions = safeParse(rawAttribute?.expandParam)
  if (expandOptions && typeof expandOptions === 'object') {
    Object.assign(options, expandOptions?.options || {})
  }
  const accessInfo = safeParse(rawAttribute?.accessInfo)
  if (accessInfo && typeof accessInfo === 'object' && accessInfo.token) {
    options.token = accessInfo.token
  }
  return options
}

/**
 * @description 构造目录树
 */
function buildCatalogTree(rawList) {
  const serviceNodeMap = new Map()
  const expandedKeys = []
  const transformNode = (node, parentInfo = null) => {
    const attr = node.Attribute || {}
    const children = Array.isArray(node.Children) ? node.Children : []
    const rid = attr.rid || node.Rid
    const label = attr.name || node.Name || '未命名图层'
    if (children.length) {
      const id = `group:${rid || label}`
      expandedKeys.push(id)
      return {
        id,
        label,
        rid,
        nodeType: 'group',
        children: children.map((child) => transformNode(child, { rid, name: label })),
      }
    }
    const serviceId = `catalog:${rid}`
    const serviceNode = {
      id: serviceId,
      label,
      rid,
      nodeType: 'service',
      parentRid: parentInfo?.rid,
      parentName: parentInfo?.name,
      serviceType: attr.serviceTypeName || '',
      url: attr.servicePath || '',
      rawAttribute: attr,
      sortValue: attr.sortValue,
    }
    serviceNodeMap.set(serviceId, serviceNode)
    return serviceNode
  }
  const tree = Array.isArray(rawList) ? rawList.map((item) => transformNode(item)) : []
  return {
    treeData: tree,
    defaultExpandedKeys: expandedKeys,
    serviceNodeMap,
  }
}

/**
 * @description 安全解析 JSON 字符串
 */
function safeParse(text) {
  if (!text || typeof text !== 'string') return null
  try {
    return JSON.parse(text)
  } catch (err) {
    return null
  }
}
</script>

<style scoped lang="scss">
.layer-directory-control {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  pointer-events: auto;
  z-index: 10;
}

.layer-directory-control__toggle {
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.92);
  color: #1f1f1f;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  backdrop-filter: blur(8px);
  pointer-events: auto;
  transition: background-color 0.2s ease, transform 0.2s ease;
}

.layer-directory-control__toggle:hover {
  background: #ffffff;
  transform: translateY(-1px);
}

.layer-directory-control__panel {
  width: 320px;
  pointer-events: auto;
}

.layer-directory-control__card {
  border-radius: 12px;
}

.layer-directory-control__card-header {
  display: flex;
  align-items: center;
}

.layer-directory-control__close {
  margin-left: auto;
  color: #909399;
}

.layer-directory-control__body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.layer-directory-control__search {
  width: 100%;
}

.layer-directory-control__scroll {
  max-height: 360px;
}

.layer-directory-control__layer-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.layer-directory-control__layer-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  border-radius: 8px;
  background: rgba(240, 248, 255, 0.6);
}

.layer-directory-control__layer-main {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 55%;
}

.layer-directory-control__layer-icon {
  font-size: 16px;
  color: #409eff;
}

.layer-directory-control__layer-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.layer-directory-control__layer-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

.layer-directory-control__layer-action-text {
  margin-left: 4px;
}

.layer-directory-fade-enter-active,
.layer-directory-fade-leave-active {
  transition: opacity 0.2s ease;
}

.layer-directory-fade-enter-from,
.layer-directory-fade-leave-to {
  opacity: 0;
}
</style>
