<template>
  <div class="model3d-view">
    <div class="toolbar">
      <input type="file" @change="handleFileUpload" accept=".fbx,.obj,.mtl" />
      <span>文件上传</span>
    </div>
    <div class="main-content">
      <!-- Three.js 渲染画布 -->
      <div class="canvas-container" ref="canvasContainer"></div>

      <!-- 右侧面板 -->
      <div class="gui-panel" ref="guiPanel"></div>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'
import * as dat from 'three/examples/jsm/libs/lil-gui.module.min.js'

// DOM refs
const canvasContainer = ref(null)
const guiPanel = ref(null)

// Three.js 场景相关
let scene, camera, renderer, controls
let modelGroup = new THREE.Group()
let gui

// 状态变量
const state = {
  autoRotate: false,
  showAxesHelper: true,
  showGridHelper: true,
  cameraPosition: [0, 5, 10]
}

onMounted(() => {
  initThree()
  initGUI()
})

function initThree() {
  // 场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xeeeeee)

  // 相机
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / 2,
    0.1,
    1000
  )
  camera.position.set(...state.cameraPosition)

  // 渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(canvasContainer.value.clientWidth, window.innerHeight * 0.8)
  canvasContainer.value.appendChild(renderer.domElement)

  // 控制器
  controls = new OrbitControls(camera, renderer.domElement)

  // 辅助线
  const axesHelper = new THREE.AxesHelper(5)
  scene.add(axesHelper)
  const gridHelper = new THREE.GridHelper(20, 20)
  scene.add(gridHelper)

  // 光照
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.6)
  scene.add(ambientLight)
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
  directionalLight.position.set(10, 10, 10)
  scene.add(directionalLight)

  // 动画循环
  function animate() {
    requestAnimationFrame(animate)
    if (state.autoRotate) {
      modelGroup.rotation.y += 0.01
    }
    controls.update()
    renderer.render(scene, camera)
  }

  animate()

  // 调整窗口大小
  window.addEventListener('resize', () => {
    camera.aspect = canvasContainer.value.clientWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(canvasContainer.value.clientWidth, window.innerHeight * 0.8)
  })
}

function initGUI() {
  gui = new dat.GUI({ autoPlace: false })
  guiPanel.value.appendChild(gui.domElement)

  // 自动旋转
  gui.add(state, 'autoRotate').name('自动旋转')

  // 显示辅助线
  gui.add(state, 'showAxesHelper').name('显示坐标轴').onChange(val => {
    scene.getObjectByName('AxesHelper').visible = val
  })

  gui.add(state, 'showGridHelper').name('显示网格').onChange(val => {
    scene.getObjectByName('GridHelper').visible = val
  })

  // 相机位置
  const cameraFolder = gui.addFolder('相机位置')
  cameraFolder.add(state.cameraPosition, 0, -10, 10).name('X')
  cameraFolder.add(state.cameraPosition, 1, -10, 10).name('Y')
  cameraFolder.add(state.cameraPosition, 2, 5, 30).name('Z').onChange(() => {
    camera.position.set(...state.cameraPosition)
  })
  cameraFolder.open()
}

function handleFileUpload(event) {
  const file = event.target.files[0]
  if (!file) return

  // 移除旧模型
  if (modelGroup.children.length > 0) {
    modelGroup.children.forEach(child => modelGroup.remove(child))
  }

  const fileName = file.name.toLowerCase()
  const reader = new FileReader()

  if (fileName.endsWith('.fbx')) {
    reader.readAsArrayBuffer(file)
    reader.onload = () => {
      const loader = new FBXLoader()
      const content = loader.parse(reader.result, '')
      modelGroup.add(content)
      scene.add(modelGroup)
    }
  } else if (fileName.endsWith('.obj')) {
    reader.readAsText(file)
    reader.onload = () => {
      const loader = new OBJLoader()
      const content = loader.parse(reader.result)
      modelGroup.add(content)
      scene.add(modelGroup)
    }
  } else if (fileName.endsWith('.mtl')) {
    alert('需要同时上传 .obj 和 .mtl 文件，请先实现多文件上传处理逻辑。')
  } else {
    alert('不支持的文件类型！')
  }
}
</script>
<style scoped>
.dialog-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.toolbar {
  padding: 10px;
  background-color: #f0f0f0;
  border-bottom: 1px solid #ccc;
}

.main-content {
  display: flex;
  flex: 1;
  overflow: hidden;
}

.canvas-container {
  flex: 3;
  position: relative;
}

.gui-panel {
  flex: 1;
  border-left: 1px solid #ccc;
  background: #fff;
  padding: 10px;
  overflow-y: auto;
}
</style>