<template>
  <div class="dxf-viewer-root">
    <div class="dxf-sidebar">
      <div class="sidebar-title">图层列表</div>
      <ul class="layer-list">
        <li
          v-for="(layer, idx) in layerList"
          :key="layer.layerName"
          :class="{ active: idx === selectedLayerIndex }"
          @click="selectLayer(idx)"
        >
          {{ layer.layerName }} <span class="entity-count">({{ layer.entities.length }})</span>
        </li>
      </ul>
    </div>
    <div class="dxf-main">
      <div class="entity-list">
        <div class="entity-title">图元列表</div>
        <ul>
          <li
            v-for="(entity, i) in selectedLayerEntities"
            :key="entity.id"
            :class="{ selected: selectedEntityId === entity.id }"
            @click="selectEntity(entity.id)"
          >
            <span class="entity-type">{{ entity.entityType }}</span>
            <span class="entity-id">#{{ entity.id }}</span>
          </li>
        </ul>
      </div>
      <div class="threejs-container" ref="threeContainer"></div>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export default {
  name: 'DxfLayerEntityViewer',
  props: {
    entities: {
      type: Array,
      required: true
    }
  },
  data() {
    return {
      layerList: [],
      selectedLayerIndex: 0,
      selectedEntityId: null,
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      entityMeshMap: {}, // id: mesh
      scaleFactor: 1, // 动态计算
      offsetX: 0,
      offsetY: 0,
      minX: 0,
      minY: 0,
      maxX: 0,
      maxY: 0
    }
  },
  computed: {
    selectedLayerEntities() {
      if (!this.layerList.length) return []
      return this.layerList[this.selectedLayerIndex].entities
    }
  },
  watch: {
    entities: {
      immediate: true,
      handler(val) {
        this.prepareLayers(val)
        this.$nextTick(() => {
          this.initThree()
        })
      }
    },
    selectedLayerIndex() {
      this.highlightEntities()
    },
    selectedEntityId() {
      this.highlightEntities()
    }
  },
  mounted() {
    window.addEventListener('resize', this.onWindowResize)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.onWindowResize)
    if (this.renderer) {
      this.renderer.dispose()
    }
  },
  methods: {
    prepareLayers(entities) {
      // 分组
      const map = {}
      entities.forEach(e => {
        if (!map[e.layerName]) map[e.layerName] = []
        map[e.layerName].push(e)
      })
      this.layerList = Object.keys(map).map(layerName => ({
        layerName,
        entities: map[layerName]
      }))
      this.selectedLayerIndex = 0
      this.selectedEntityId = null
    },
    selectLayer(idx) {
      this.selectedLayerIndex = idx
      this.selectedEntityId = null
    },
    selectEntity(id) {
      this.selectedEntityId = id
    },
    initThree() {
      // 清理
      if (this.renderer && this.$refs.threeContainer) {
        this.$refs.threeContainer.innerHTML = ''
      }
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        60,
        this.$refs.threeContainer.clientWidth / this.$refs.threeContainer.clientHeight,
        0.1,
        100000
      )
      this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
      this.renderer.setSize(
        this.$refs.threeContainer.clientWidth,
        this.$refs.threeContainer.clientHeight
      )
      this.renderer.setClearColor(0xf0f2f5, 1)
      this.$refs.threeContainer.appendChild(this.renderer.domElement)
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.enableDamping = true
      this.controls.dampingFactor = 0.05
      this.controls.screenSpacePanning = true
      // 灯光
      this.scene.add(new THREE.AmbientLight(0xffffff, 0.6))
      const dirLight = new THREE.DirectionalLight(0xffffff, 0.8)
      dirLight.position.set(100, 100, 100)
      this.scene.add(dirLight)
      // 网格
      const gridHelper = new THREE.GridHelper(100, 10, 0x444444, 0x888888)
      this.scene.add(gridHelper)
      // 坐标轴
      const axesHelper = new THREE.AxesHelper(50)
      this.scene.add(axesHelper)
      // 渲染实体
      this.renderAllEntities()
      this.animate()
    },
    renderAllEntities() {
      // 计算边界
      let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity
      this.entityMeshMap = {}
      this.entities.forEach(entity => {
        const geometry = entity.geometry ? JSON.parse(entity.geometry) : null
        if (!geometry) return
        if (entity.entityType === 'LINE') {
          if (Array.isArray(geometry.start)) {
            minX = Math.min(minX, geometry.start[0], geometry.end[0])
            minY = Math.min(minY, geometry.start[1], geometry.end[1])
            maxX = Math.max(maxX, geometry.start[0], geometry.end[0])
            maxY = Math.max(maxY, geometry.start[1], geometry.end[1])
          }
        } else if (entity.entityType === 'CIRCLE') {
          if (Array.isArray(geometry.center)) {
            minX = Math.min(minX, geometry.center[0] - geometry.radius)
            minY = Math.min(minY, geometry.center[1] - geometry.radius)
            maxX = Math.max(maxX, geometry.center[0] + geometry.radius)
            maxY = Math.max(maxY, geometry.center[1] + geometry.radius)
          }
        }
      })
      this.minX = minX
      this.minY = minY
      this.maxX = maxX
      this.maxY = maxY
      this.offsetX = (minX + maxX) / 2
      this.offsetY = (minY + maxY) / 2
    
      // 缩放适配，保持宽高比
      const containerWidth = this.$refs.threeContainer.clientWidth
      const containerHeight = this.$refs.threeContainer.clientHeight
      const rangeX = maxX - minX
      const rangeY = maxY - minY
      const scaleX = (containerWidth * 0.8) / rangeX
      const scaleY = (containerHeight * 0.8) / rangeY
      this.scaleFactor = Math.min(scaleX, scaleY)
    
      // 渲染
      this.entities.forEach(entity => {
        const geometry = entity.geometry ? JSON.parse(entity.geometry) : null
        if (!geometry) return
        const color = this.getColor(entity.color)
        const material = new THREE.LineBasicMaterial({ color, linewidth: 1 })
        let mesh = null
        if (entity.entityType === 'LINE') {
          const start = this.transformPoint(geometry.start)
          const end = this.transformPoint(geometry.end)
          const points = [start, end]
          const lineGeometry = new THREE.BufferGeometry().setFromPoints(points)
          mesh = new THREE.Line(lineGeometry, material)
        } else if (entity.entityType === 'CIRCLE') {
          const center = this.transformPoint(geometry.center)
          const radius = geometry.radius * this.scaleFactor
          const circleGeometry = new THREE.CircleGeometry(radius, 64)
          mesh = new THREE.LineLoop(circleGeometry, material)
          mesh.position.set(center.x, center.y, center.z)
        }
        if (mesh) {
          mesh.userData = { entityId: entity.id, layerName: entity.layerName }
          this.scene.add(mesh)
          this.entityMeshMap[entity.id] = mesh
        }
      })
      // 居中相机
      this.camera.position.set(0, 0, Math.max(containerWidth, containerHeight))
      this.camera.lookAt(0, 0, 0)
      if (this.controls) this.controls.update()
      this.highlightEntities()
    },
    transformPoint(point) {
      return new THREE.Vector3(
        (point[0] - this.offsetX) * this.scaleFactor,
        (point[1] - this.offsetY) * this.scaleFactor,
        0
      )
    },
    highlightEntities() {
      // 只高亮当前层和选中实体
      Object.values(this.entityMeshMap).forEach(mesh => {
        mesh.material.color.set(0xcccccc)
        mesh.material.linewidth = 2
      })
      // 高亮当前层
      const currentLayer = this.layerList[this.selectedLayerIndex]
      if (currentLayer) {
        currentLayer.entities.forEach(entity => {
          const mesh = this.entityMeshMap[entity.id]
          if (mesh) mesh.material.color.set(0x409EFF)
        })
      }
      // 高亮选中实体
      if (this.selectedEntityId) {
        const mesh = this.entityMeshMap[this.selectedEntityId]
        if (mesh) mesh.material.color.set(0xff0000)
      }
    },
    transformPoint(point) {
      return new THREE.Vector3(
        (point[0] - this.offsetX) * this.scaleFactor,
        (point[1] - this.offsetY) * this.scaleFactor,
        0
      )
    },
    getColor(colorIndex) {
      const colors = {
        1: 0xff0000, 2: 0xffff00, 3: 0x00ff00, 4: 0x00ffff,
        5: 0x0000ff, 6: 0xff00ff, 7: 0xffffff, 256: 0x000000
      }
      return colors[colorIndex] || 0x00aaff
    },
    animate() {
      requestAnimationFrame(this.animate)
      if (this.controls) this.controls.update()
      if (this.renderer && this.scene && this.camera) {
        this.renderer.render(this.scene, this.camera)
      }
    },
    onWindowResize() {
      if (this.camera && this.renderer && this.$refs.threeContainer) {
        this.camera.aspect = this.$refs.threeContainer.clientWidth / this.$refs.threeContainer.clientHeight
        this.camera.updateProjectionMatrix()
        this.renderer.setSize(
          this.$refs.threeContainer.clientWidth,
          this.$refs.threeContainer.clientHeight
        )
      }
    }
  }
}
</script>

<style scoped>
.dxf-viewer-root {
  display: flex;
  width: 100%;
  height: 600px;
  background: #f0f2f5;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.dxf-sidebar {
  width: 200px;
  background: #fff;
  border-right: 1px solid #e4e7ed;
  padding: 0 0 0 0;
  overflow-y: auto;
}
.sidebar-title {
  font-weight: bold;
  font-size: 16px;
  padding: 16px 0 8px 20px;
  border-bottom: 1px solid #e4e7ed;
}
.layer-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.layer-list li {
  padding: 12px 20px;
  cursor: pointer;
  border-left: 4px solid transparent;
  transition: background 0.2s, border-color 0.2s;
}
.layer-list li.active {
  background: #f0f7ff;
  border-left: 4px solid #409EFF;
  color: #409EFF;
}
.entity-count {
  color: #909399;
  font-size: 12px;
  margin-left: 8px;
}
.dxf-main {
  flex: 1;
  display: flex;
  flex-direction: row;
  height: 100%;
}
.entity-list {
  width: 220px;
  background: #f7f9fc;
  border-right: 1px solid #e4e7ed;
  padding: 0 0 0 0;
  overflow-y: auto;
}
.entity-title {
  font-weight: bold;
  font-size: 15px;
  padding: 16px 0 8px 20px;
  border-bottom: 1px solid #e4e7ed;
}
.entity-list ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.entity-list li {
  padding: 10px 20px;
  cursor: pointer;
  border-left: 4px solid transparent;
  transition: background 0.2s, border-color 0.2s;
  display: flex;
  align-items: center;
  gap: 8px;
}
.entity-list li.selected {
  background: #fff7f7;
  border-left: 4px solid #ff4d4f;
  color: #ff4d4f;
}
.entity-type {
  font-weight: 600;
  font-size: 13px;
}
.entity-id {
  color: #bbb;
  font-size: 12px;
}
.threejs-container {
  flex: 1;
  height: 100%;
  background: #f0f2f5;
  position: relative;
}
</style>