<!--
  Model3DView.vue
  3D模型视图组件
  负责加载、渲染和交互3D模型
-->
<template>
  <div ref="containerRef" class="w-full h-full relative overflow-hidden">
    <!-- 加载遮罩 -->
    <LoadingOverlay :is-loading="isLoading" />

    <!-- 工具栏 -->
    <ModelToolbar
      :auto-rotate="autoRotate"
      :is-maximized="isMaximized || false"
      :lighting-mode="lightingMode"
      :double-sided="doubleSided"
      :show-download="isFullMode"
      @reset-view="resetView"
      @toggle-auto-rotate="toggleAutoRotate"
      @toggle-maximize="emit('toggleMaximize')"
      @toggle-lighting="toggleLighting"
      @toggle-double-side="toggleDoubleSide"
      @export-model="exportModel"
      @export-hierarchy="exportHierarchy"
    />

    <!-- 视图控制 -->
    <ViewControls @set-standard-view="setStandardView" />
  </div>
</template>

<script setup lang="ts">
/**
 * Model3DView 组件
 * 3D模型的主视图组件，负责模型的加载、渲染和交互
 */
import * as THREE from 'three'
import { nextTick } from 'vue'
import { useInteraction } from '~/composables/powerStation/useInteraction'
import { useModelManager } from '~/composables/powerStation/useModelManager'
import { useThreeScene } from '~/composables/powerStation/useThreeScene'
import { usePowerStationStore } from '~/stores/powerStation'
import LoadingOverlay from './Model3D/LoadingOverlay.vue'
import ModelToolbar from './Model3D/ModelToolbar.vue'
import ViewControls from './Model3D/ViewControls.vue'

// ============================================================
// Props 和 Emits
// ============================================================

const props = defineProps<{
  /** 是否最大化 */
  isMaximized?: boolean
}>()

const emit = defineEmits(['toggleMaximize'])

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

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

// ============================================================
// Three.js 场景系统
// ============================================================

const {
  containerRef,
  initThree,
  getScene,
  getCamera,
  getRenderer,
  getControls,
  getComposer,
  addAnimateCallback,
  addResizeCallback,
  onWindowResize,
  setStandardView,
} = useThreeScene()

// ============================================================
// 模型管理系统
// ============================================================

const {
  modelGroup,
  isLoading,
  lightingMode,
  objectMap,
  initModelSystem,
  loadModel,
  processModel,
  fitView,
  toggleLighting,
  archetypeModel,
  findNodeById,
  loadModelByFileName,
} = useModelManager(getScene, getCamera, getControls, getRenderer)

// ============================================================
// 交互系统
// ============================================================

const {
  initInteraction,
  highlightClick,
  updatePassSize,
  dispose: disposeInteraction,
} = useInteraction(
  getScene,
  getCamera,
  getComposer,
  () => containerRef.value,
  modelGroup,
  () => archetypeModel.value
)

// ============================================================
// 本地状态
// ============================================================

/** 自动旋转状态 */
const autoRotate = ref(false)
/** 双面渲染状态 */
const doubleSided = ref(false)

// ============================================================
// 计算属性
// ============================================================

/** 是否为完整模式 */
const isFullMode = computed(() => store.loadMode)

// ============================================================
// 视图控制方法
// ============================================================

/**
 * 切换自动旋转
 */
const toggleAutoRotate = () => {
  autoRotate.value = !autoRotate.value
}

/**
 * 切换双面渲染
 * 使用 shader 方式实现，通过修改材质的 side 属性
 */
const toggleDoubleSide = () => {
  doubleSided.value = !doubleSided.value
  const scene = getScene()
  if (!scene) return

  // 遍历场景中所有物体，修改材质的渲染面属性
  scene.traverse((child: THREE.Object3D) => {
    if ((child as THREE.Mesh).isMesh) {
      const mesh = child as THREE.Mesh
      const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material]

      materials.forEach((mat: THREE.Material) => {
        if (doubleSided.value) {
          // 保存原始的 side 值，然后设置为 DoubleSide
          if (mat.userData.originalSide === undefined) {
            mat.userData.originalSide = mat.side
          }
          mat.side = THREE.DoubleSide
        } else {
          // 恢复原始的 side 值
          if (mat.userData.originalSide !== undefined) {
            mat.side = mat.userData.originalSide
          } else {
            mat.side = THREE.FrontSide
          }
        }
        mat.needsUpdate = true
      })
    }
  })
}

/**
 * 重置视图
 */
const resetView = async () => {
  const rootPath = store.currentNodeId || archetypeModel.value?.name || 'root'
  await navigateTo({
    query: {
      ...route.query,
      currentNodeId: rootPath,
    },
  })
}

// ============================================================
// 导出功能
// ============================================================

/**
 * 导出GLB模型
 */
const exportModel = async () => {
  try {
    if (!modelGroup.children.length) {
      ElMessage.warning('没有可导出的模型')
      return
    }

    const currentModel = modelGroup.children[0]
    if (!currentModel) {
      ElMessage.warning('未找到当前模型')
      return
    }

    // 克隆模型用于导出
    const exportModelClone = currentModel.clone()

    // 清理循环引用
    cleanCircularReferences(exportModelClone)

    // 转换材质为GLTF兼容格式
    convertMaterialsToGLTFCompatible(exportModelClone)

    // 生成模型名称
    const modelName = store.currentNodeId || '模型'

    // 创建导出场景
    const exportScene = new THREE.Scene()
    exportScene.add(exportModelClone)

    // 使用GLTFExporter导出
    const { GLTFExporter } = await import('three/examples/jsm/exporters/GLTFExporter.js')
    const exporter = new GLTFExporter()

    exporter.parse(
      exportScene,
      gltf => {
        const glbData = new Blob([gltf], { type: 'model/gltf-binary' })
        downloadBlob(glbData, `${modelName}.glb`)
        ElMessage.success(`模型 ${modelName}.glb 导出成功`)
      },
      error => {
        console.error('导出失败:', error)
        ElMessage.error('模型导出失败')
      },
      { binary: true }
    )
  } catch (error) {
    console.error('导出错误:', error)
    ElMessage.error('导出过程中发生错误')
  }
}

/**
 * 导出层级关系JSON
 */
const exportHierarchy = () => {
  try {
    if (!modelGroup.children.length) {
      ElMessage.warning('没有可导出的模型层级')
      return
    }

    if (!archetypeModel.value) {
      ElMessage.warning('未找到archetypeModel')
      return
    }

    const modelName = store.currentNodeId || '模型'
    const hierarchyData = buildHierarchy(archetypeModel.value)
    const jsonData = JSON.stringify(hierarchyData, null, 2)

    const blob = new Blob([jsonData], { type: 'application/json' })
    downloadBlob(blob, `${modelName}~hierarchy.json`)

    ElMessage.success(`物体层级关系 ${modelName}~hierarchy.json 导出成功`)
  } catch (error) {
    console.error('导出层级关系错误:', error)
    ElMessage.error('导出层级关系失败')
  }
}

// ============================================================
// 导出辅助函数
// ============================================================

/**
 * 清理循环引用
 */
const cleanCircularReferences = (object: THREE.Object3D) => {
  object.traverse(child => {
    if ((child as THREE.Mesh).isMesh) {
      const mesh = child as THREE.Mesh
      const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material]

      materials.forEach(mat => {
        if (mat.userData) {
          delete mat.userData.lambertPartner
          delete mat.userData.pbrPartner
        }
      })
    }
  })
}

/**
 * 转换材质为GLTF兼容格式
 */
const convertMaterialsToGLTFCompatible = (object: THREE.Object3D) => {
  object.traverse(child => {
    if ((child as THREE.Mesh).isMesh) {
      const mesh = child as THREE.Mesh
      const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material]

      const newMaterials = materials.map(mat => {
        if (mat.type === 'MeshStandardMaterial' || mat.type === 'MeshBasicMaterial') {
          return mat
        }

        const originalMap = (mat as any).map || null
        const useAlpha = originalMap !== null

        const standardMat = new THREE.MeshStandardMaterial({
          color: (mat as any).color || new THREE.Color(0xaaaaaa),
          map: originalMap,
          alphaMap: originalMap,
          normalMap: (mat as any).normalMap || null,
          transparent: useAlpha || (mat as any).transparent || false,
          opacity: useAlpha ? 1 : (mat as any).opacity || 1,
          side: mat.side || THREE.FrontSide,
          metalness: 0.6,
          roughness: 0.6,
        })

        if (mat.userData) {
          standardMat.userData = { ...mat.userData }
        }

        return standardMat
      })

      mesh.material = Array.isArray(mesh.material) ? newMaterials : newMaterials[0]
    }
  })
}

/**
 * 构建层级结构
 */
const buildHierarchy = (object: THREE.Object3D): any => {
  const obj: any = {
    id: object.uuid,
    name: object.name,
    type: object.type,
    children: [],
  }

  object.children.forEach(child => {
    obj.children.push(buildHierarchy(child))
  })

  return obj
}

/**
 * 下载Blob文件
 */
const downloadBlob = (blob: Blob, filename: string) => {
  const url = URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
  URL.revokeObjectURL(url)
}

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

// 监听最大化状态变化
watch(
  () => props.isMaximized,
  () => {
    setTimeout(() => {
      onWindowResize()
      fitView()
    }, 350)
  }
)

// 路由监听器（核心逻辑入口）
watch(
  () => route.query.currentNodeId,
  newId => {
    const id = newId as string
    console.log('路由currentNodeId变化:', id)

    // 确保store的currentNodeId与路由参数一致
    if (id) {
      store.currentNodeId = id
      store.selectNode({ id })
    } else {
      store.currentNodeId = ''
      store.selectNode({ id: '' })
    }

    if (isFullMode.value) {
      // 完整模式：处理模型
      if (archetypeModel.value) {
        processModel(id, true)
      }
    } else {
      // 简化模式：直接加载对应文件
      if (id) {
        loadModelByFileName(id)
      }
    }
  },
  { immediate: true }
)

// 选择监听器
watch(
  () => store.currentNodeId,
  async newId => {
    console.log('选择监听器触发:', newId)

    if (!newId) {
      highlightClick(null)
      return
    }

    const currentRouteNodeId = route.query.currentNodeId as string

    // 等待模型加载完成
    let retryCount = 0
    const maxRetries = 5
    while (isLoading.value && retryCount < maxRetries) {
      console.log(`模型加载中，等待加载完成后再处理高亮 (重试 ${retryCount + 1}/${maxRetries})`)
      await nextTick()
      await new Promise(resolve => setTimeout(resolve, 100))
      retryCount++
    }

    let obj = objectMap.get(newId)
    console.log('直接找到物体:', obj ? obj.name : 'null')

    // 如果未找到精确对象，尝试查找可见的祖先
    if (!obj && archetypeModel.value) {
      console.log('搜索可见祖先...')
      let current = findNodeById(archetypeModel.value, newId)
      while (current) {
        console.log('检查祖先:', current.name, current.userData.id)
        if (current.userData.id && objectMap.has(current.userData.id)) {
          obj = objectMap.get(current.userData.id)
          console.log('找到可见祖先:', obj?.name)
          break
        }
        current = current.parent
      }
    }

    if (obj) {
      highlightClick(obj)
    } else {
      console.warn('未找到ID对应的对象:', newId)
      highlightClick(null)
    }

    if (newId === currentRouteNodeId) {
      highlightClick(null)
      return
    }
  },
  { immediate: true }
)

// ============================================================
// 聚焦事件处理
// ============================================================

/**
 * 处理聚焦事件
 */
const handleFocusEvent = (nodeId: string) => {
  console.log('聚焦事件触发:', nodeId)

  let obj = objectMap.get(nodeId)

  // 如果未找到精确对象，尝试查找可见的祖先
  if (!obj && archetypeModel.value) {
    console.log('搜索可见祖先...')
    let current = findNodeById(archetypeModel.value, nodeId)
    while (current) {
      console.log('检查祖先:', current.name, current.userData.id)
      if (current.userData.id && objectMap.has(current.userData.id)) {
        obj = objectMap.get(current.userData.id)
        console.log('找到可见祖先:', obj?.name)
        break
      }
      current = current.parent
    }
  }

  if (obj) {
    highlightClick(obj)
    fitView(obj, true)
    console.log('已聚焦到物体:', obj.name)
  } else {
    console.warn('未找到ID对应的对象:', nodeId)
  }
}

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

onMounted(() => {
  // 1. 初始化Three.js
  initThree()

  // 2. 初始化模型系统
  initModelSystem()

  // 3. 初始化交互
  initInteraction()

  const currentId = route.query.currentNodeId as string

  // 4. 根据模式加载模型
  if (isFullMode.value) {
    loadModel(`/3DModels/${currentId}.glb`, () => {
      const currentId =
        (route.query.currentNodeId as string) ||
        store.currentNodeId ||
        archetypeModel.value?.name ||
        'root'
      processModel(currentId, true)
    })
  } else {
    loadModelByFileName(currentId)
  }

  // 5. 设置动画循环钩子
  addAnimateCallback(() => {
    const controls = getControls()
    if (controls) {
      controls.autoRotate = autoRotate.value
    }
  })

  // 6. 设置尺寸调整钩子
  addResizeCallback(() => {
    if (containerRef.value) {
      const width = containerRef.value.clientWidth
      const height = containerRef.value.clientHeight
      updatePassSize(width, height)
    }
  })

  // 7. 添加聚焦事件监听器
  store.addFocusListener(handleFocusEvent)
})

onUnmounted(() => {
  disposeInteraction()
  store.removeFocusListener(handleFocusEvent)
})
</script>
