<!--
  ModelTreePanel.vue
  模型结构树面板组件
  显示3D模型的层级结构，支持搜索、节点选择和聚焦
-->
<template>
  <div class="relative">
    <div
      class="bg-[#0b1120] h-full border-r border-cyan-500/20 flex flex-col transition-all duration-300"
    >
      <!-- ============================================================
           搜索头部
           ============================================================ -->
      <div class="p-4 bg-[#0f172a] border-b border-cyan-500/20">
        <div class="flex items-center justify-between mb-3">
          <h2 class="text-base font-bold text-cyan-400 flex items-center font-mono tracking-wide">
            <el-icon class="mr-2"><Files /></el-icon>
            模型结构
          </h2>
        </div>
        <el-input
          v-model="filterText"
          placeholder="搜索节点..."
          prefix-icon="Search"
          clearable
          class="tech-input"
        />
      </div>

      <!-- ============================================================
           树内容
           ============================================================ -->
      <div
        ref="treeContainer"
        class="flex-1 overflow-y-auto overflow-x-hidden py-2 custom-scrollbar min-h-0"
      >
        <el-tree
          ref="treeRef"
          :data="store.modelHierarchy"
          :props="defaultProps"
          node-key="id"
          :filter-node-method="filterNodeMethod"
          highlight-current
          default-expand-all
          class="tech-tree"
          @node-click="handleNodeClick"
          @node-expand="handleNodeExpand"
          @node-collapse="handleNodeCollapse"
        >
          <template #default="{ node }">
            <div
              :id="'tree-node-' + node.data.id"
              class="flex items-center gap-2 text-sm w-full pr-2 group select-none py-1"
              @dblclick="handleNodeDblClick(node.data)"
              @mousedown.prevent="$event.preventDefault()"
              @selectstart.prevent="$event.preventDefault()"
            >
              <!-- 节点图标 -->
              <el-icon v-if="!node.isLeaf" class="text-cyan-500"><Folder /></el-icon>
              <el-icon v-else class="text-blue-400"><Document /></el-icon>

              <!-- 节点标签 -->
              <span
                class="truncate flex-1 font-mono text-gray-400 group-hover:text-cyan-300 transition-colors"
                :title="node.label"
              >
                {{ node.label }}
              </span>

              <!-- 聚焦按钮 -->
              <el-tooltip content="聚焦视图" placement="right" :show-after="500" effect="dark">
                <el-icon
                  class="text-cyan-500/50 hover:text-cyan-400 cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity"
                  @click.stop="handleZoom(node.data)"
                >
                  <ZoomIn />
                </el-icon>
              </el-tooltip>
            </div>
          </template>
        </el-tree>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
/**
 * ModelTreePanel 组件
 * 显示模型的层级结构树，支持搜索、选择和聚焦功能
 */
import { Document, Files, Folder, ZoomIn } from '@element-plus/icons-vue'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { usePowerStationStore } from '~/stores/powerStation'

// ============================================================
// 状态和引用
// ============================================================

const store = usePowerStationStore()
const route = useRoute()

/** 过滤文本 */
const filterText = ref('')
/** 树组件引用 */
const treeRef = ref()
/** 树容器引用 */
const treeContainer = ref<HTMLElement>()
/** 是否折叠 */
const isCollapsed = ref(false)
/** 是否为内部选择（来自树本身的选择） */
const isInternalSelection = ref(false)
/** 已展开的节点ID集合 */
const expandedKeys = ref<Set<string>>(new Set())

/** 树组件属性配置 */
const defaultProps = {
  value: 'id',
  label: 'label',
  children: 'children',
}

// ============================================================
// 响应式布局
// ============================================================

/**
 * 更新布局状态
 * 根据窗口宽度自动折叠
 */
const updateLayout = () => {
  if (window.innerWidth < 1200) {
    isCollapsed.value = true
  } else {
    isCollapsed.value = false
  }
}

/**
 * 切换折叠状态
 */
const toggleCollapse = () => {
  isCollapsed.value = !isCollapsed.value
}

// ============================================================
// 过滤功能
// ============================================================

// 监听过滤文本变化
watch(filterText, val => {
  treeRef.value?.filter(val)
})

/**
 * 节点过滤方法
 * @param value - 过滤值
 * @param data - 节点数据
 * @returns 是否显示该节点
 */
const filterNodeMethod = (value: string, data: any) => {
  if (!value) return true
  const searchValue = value.toLowerCase()
  const label = data.label?.toLowerCase() || ''
  return label.includes(searchValue)
}

// ============================================================
// 节点操作
// ============================================================

/**
 * 处理节点点击
 * @param data - 节点数据
 */
const handleNodeClick = (data: any) => {
  // 更新store选择状态
  store.selectNode(data)
  // 标记为内部选择
  isInternalSelection.value = true

  // 移动设备上自动折叠
  if (window.innerWidth < 1024) {
    isCollapsed.value = true
  }
}

/**
 * 处理缩放/聚焦操作
 * @param data - 节点数据
 */
const handleZoom = (data: any) => {
  store.selectNode(data)
  store.triggerFocus(data.id)
}

/**
 * 处理节点双击
 * @param data - 节点数据
 */
const handleNodeDblClick = async (data: any) => {
  await navigateTo({
    query: {
      ...route.query,
      currentNodeId: data.id,
    },
  })
}

/**
 * 处理节点展开
 * @param data - 节点数据
 */
const handleNodeExpand = (data: any) => {
  expandedKeys.value.add(data.id)
}

/**
 * 处理节点折叠
 * @param data - 节点数据
 */
const handleNodeCollapse = (data: any) => {
  expandedKeys.value.delete(data.id)
}

// ============================================================
// 辅助函数
// ============================================================

/**
 * 查找节点路径
 * @param nodes - 节点数组
 * @param targetId - 目标ID
 * @param path - 当前路径
 * @returns 路径数组或null
 */
const findPath = (nodes: any[], targetId: string, path: string[] = []): string[] | null => {
  for (const node of nodes) {
    if (node.id === targetId) {
      return path
    }
    if (node.children && node.children.length > 0) {
      const result = findPath(node.children, targetId, [...path, node.id])
      if (result) return result
    }
  }
  return null
}

// ============================================================
// 监听器
// ============================================================

// 监听store选择变化（3D视图 -> 树）
watch(
  () => store.currentNodeId,
  newId => {
    if (!treeRef.value) return

    // 如果是内部选择，不需要滚动/展开
    if (isInternalSelection.value) {
      isInternalSelection.value = false
      return
    }

    if (!newId) {
      treeRef.value.setCurrentKey(null)
      return
    }

    // 1. 高亮节点
    try {
      treeRef.value.setCurrentKey(newId)
    } catch (e) {
      console.warn('设置当前键失败:', e)
    }

    // 2. 查找路径并展开/滚动
    const path = findPath(store.modelHierarchy, newId)
    if (path) {
      // 更新展开状态
      path.forEach(id => expandedKeys.value.add(id))

      // 同步树展开状态
      path.forEach(id => {
        const node = treeRef.value.getNode(id)
        if (node) {
          node.expanded = true
        }
      })

      // 延迟滚动，等待DOM更新
      setTimeout(() => {
        requestAnimationFrame(() => {
          try {
            const element = document.getElementById('tree-node-' + newId)
            if (element) {
              element.scrollIntoView({ behavior: 'smooth', block: 'center' })
            }
          } catch (e) {
            console.warn('树滚动错误:', e)
          }
        })
      }, 300)
    }
  }
)

// ============================================================
// 生命周期
// ============================================================

onMounted(() => {
  updateLayout()
  window.addEventListener('resize', updateLayout)
})

onUnmounted(() => {
  window.removeEventListener('resize', updateLayout)
})
</script>

<style scoped>
/* ============================================================
   输入框样式
   ============================================================ */

:deep(.tech-input .el-input__wrapper) {
  background-color: rgba(15, 23, 42, 0.5);
  box-shadow: 0 0 0 1px rgba(34, 211, 238, 0.2) inset;
}

:deep(.tech-input .el-input__inner) {
  color: #e2e8f0;
  font-family: monospace;
}

:deep(.tech-input .el-input__wrapper.is-focus) {
  box-shadow: 0 0 0 1px #06b6d4 inset;
}

/* ============================================================
   树样式
   ============================================================ */

.tech-tree {
  background: transparent;
  color: #94a3b8;
}

:deep(.el-tree-node__content) {
  background-color: transparent !important;
  height: 32px;
}

:deep(.el-tree-node__content:hover) {
  background-color: rgba(6, 182, 212, 0.1) !important;
}

:deep(.el-tree-node.is-current > .el-tree-node__content) {
  background-color: rgba(6, 182, 212, 0.15) !important;
  border-right: 2px solid #22d3ee;
}

:deep(.el-tree-node.is-current > .el-tree-node__content .truncate) {
  color: #22d3ee !important;
  font-weight: bold;
}

/* ============================================================
   滚动条样式
   ============================================================ */

.custom-scrollbar::-webkit-scrollbar {
  width: 6px;
}

.custom-scrollbar::-webkit-scrollbar-track {
  background: rgba(15, 23, 42, 0.5);
}

.custom-scrollbar::-webkit-scrollbar-thumb {
  background: rgba(34, 211, 238, 0.2);
  border-radius: 3px;
}

.custom-scrollbar::-webkit-scrollbar-thumb:hover {
  background: rgba(34, 211, 238, 0.4);
}
</style>
