<template>
  <!-- 模板部分保持不变 -->
  <div class="urdf-viewer-container">
    
    <div ref="viewerContainer" class="urdf-viewer"></div>

    <div v-if="isLoading" class="loading-overlay">
      <div class="loading-spinner"></div>
      <p>正在解析URDF并加载模型...</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch, reactive, computed } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import URDFLoader from 'urdf-loader'

const props = defineProps({
  basePath: { type: String, required: true },
  urdfPath: { type: String, required: true },
  modelColor: { type: String, default: '#cbcbcb' },
  showJointLimits: { type: Boolean, default: true }
})

const emits = defineEmits(['computedChange'])

const viewerContainer = ref(null)
const isLoading = ref(false)

// Three.js 核心对象
let scene = null
let camera = null
let renderer = null
let controls = null
let robot = null

// 关节控制相关状态
const jointControls = reactive([])
const availableJoints = ref({})

/**
 * 从URDF XML中提取关节信息（使用浏览器原生DOMParser）
 */
const extractJointInfoFromURDF = (urdfXml) => {
  try {
    const joints = []
    const parser = new DOMParser()
    const xmlDoc = parser.parseFromString(urdfXml, 'text/xml')
    
    // 检查解析错误
    const parseError = xmlDoc.getElementsByTagName('parsererror')
    if (parseError.length > 0) {
      throw new Error('XML解析错误: ' + parseError[0].textContent)
    }
    
    // 获取所有joint元素
    const jointElements = xmlDoc.getElementsByTagName('joint')
    
    for (let i = 0; i < jointElements.length; i++) {
      const jointElement = jointElements[i]
      const name = jointElement.getAttribute('name')
      const type = jointElement.getAttribute('type')
      
      // 只处理可动关节
      if (type && ['revolute', 'continuous', 'prismatic'].includes(type)) {
        const jointInfo = {
          name: name,
          displayName: name.replace(/_/g, ' '),
          type: type,
          value: 0,
          step: 0.01
        }
        
        // 提取关节限制
        const limitElements = jointElement.getElementsByTagName('limit')
        if (limitElements.length > 0) {
          const limit = limitElements[0]
          const lower = limit.getAttribute('lower')
          const upper = limit.getAttribute('upper')
          const effort = limit.getAttribute('effort')
          const velocity = limit.getAttribute('velocity')
          
          // 处理旋转关节
          if (type === 'revolute' || type === 'continuous') {
            jointInfo.min = lower !== null ? parseFloat(lower) : 
                          (type === 'revolute' ? -Math.PI : -Math.PI)
            jointInfo.max = upper !== null ? parseFloat(upper) : 
                          (type === 'revolute' ? Math.PI : Math.PI)
          }
          // 处理平移关节
          else if (type === 'prismatic') {
            jointInfo.min = lower !== null ? parseFloat(lower) : -1.0
            jointInfo.max = upper !== null ? parseFloat(upper) : 1.0
            jointInfo.step = 0.001
          }
          
          if (effort) jointInfo.maxEffort = parseFloat(effort)
          if (velocity) jointInfo.maxVelocity = parseFloat(velocity)
        } else {
          // 如果没有限制，设置默认范围
          if (type === 'continuous') {
            jointInfo.min = -Math.PI
            jointInfo.max = Math.PI
          } else if (type === 'revolute') {
            jointInfo.min = -Math.PI / 2
            jointInfo.max = Math.PI / 2
          } else if (type === 'prismatic') {
            jointInfo.min = -0.5
            jointInfo.max = 0.5
          }
        }
        
        // 提取关节轴
        const axisElements = jointElement.getElementsByTagName('axis')
        if (axisElements.length > 0) {
          const axis = axisElements[0].getAttribute('xyz')
          if (axis) {
            const axisValues = axis.split(' ').map(Number)
            jointInfo.axis = new THREE.Vector3(...axisValues)
          }
        }
        
        // 提取关节原点
        const originElements = jointElement.getElementsByTagName('origin')
        if (originElements.length > 0) {
          const origin = originElements[0]
          const xyz = origin.getAttribute('xyz')
          const rpy = origin.getAttribute('rpy')
          
          if (xyz) jointInfo.origin = xyz.split(' ').map(Number)
          if (rpy) jointInfo.orientation = rpy.split(' ').map(Number)
        }
        
        joints.push(jointInfo)
      }
    }
    
    // 按关节名称排序
    joints.sort((a, b) => a.name.localeCompare(b.name))
    
    console.log('从URDF提取的关节信息:', joints)
    return joints
    
  } catch (error) {
    console.error('解析URDF失败:', error)
    return []
  }
}

/**
 * 初始化Three.js场景
 */
const initScene = () => {
  const container = viewerContainer.value

  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xf0f0f0)

  camera = new THREE.PerspectiveCamera(
    75,
    container.clientWidth / container.clientHeight,
    0.01,
    1000
  )
  camera.position.set(2, 2, 3)

  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(container.clientWidth, container.clientHeight)
  container.appendChild(renderer.domElement)

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

  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
}

/**
 * 加载URDF机器人模型
 */
const loadRobot = async () => {
  isLoading.value = true
  
  try {
    // 清除现有模型
    if (robot) {
      scene.remove(robot)
      jointControls.length = 0
      availableJoints.value = {}
    }

    // 1. 加载URDF文件内容
    const urdfUrl = `${props.basePath}${props.urdfPath}`
    const response = await fetch(urdfUrl)
    const urdfXml = await response.text()
    
    // 2. 解析URDF提取关节信息（同步调用）
    const extractedJoints = extractJointInfoFromURDF(urdfXml)
    
    // 3. 使用URDFLoader加载模型
    const manager = new THREE.LoadingManager()
    const loader = new URDFLoader(manager)
    
    loader.packages = { '': props.basePath }
    
    robot = await new Promise((resolve, reject) => {
      loader.load(urdfUrl, resolve, undefined, reject)
    })
    
    // 4. 坐标轴修正
    robot.rotation.x = -Math.PI / 2
    robot.rotation.z = Math.PI / 2
    robot.updateMatrixWorld(true)

    // 应用颜色
    robot.traverse((child) => {
      if (child.isMesh && child.material) {
        child.material.color.set(props.modelColor)
      }
    })

    scene.add(robot)
    
    // 5. 初始化关节控制系统
    availableJoints.value = robot.joints
    
    // 将提取的关节信息与加载的关节匹配
    extractedJoints.forEach(jointInfo => {
      if (availableJoints.value[jointInfo.name]) {
        // 获取当前关节值
        const currentValue = availableJoints.value[jointInfo.name].jointValue || 0
        
        // 确保初始值在限制范围内
        let initialValue = currentValue
        if (props.showJointLimits) {
          initialValue = Math.max(jointInfo.min, Math.min(jointInfo.max, currentValue))
        }
        
        // 添加到控制列表
        jointControls.push({
          ...jointInfo,
          value: initialValue
        })
        
        // 设置初始关节位置
        availableJoints.value[jointInfo.name].setJointValue(initialValue)
      } else {
        console.warn(`关节 ${jointInfo.name} 在URDF模型中不存在或不可控`)
      }
    })
    
    fitCameraToObject(robot)
    
  } catch (error) {
    console.error('加载URDF模型失败:', error)
  } finally {
    isLoading.value = false
  }
}

/**
 * 更新关节角度
 */
const updateJointAngle = (jointName, angle) => {
  if (availableJoints.value[jointName]) {
    try {
      // 应用限制（如果启用）
      let clampedAngle = angle
      if (props.showJointLimits) {
        const jointInfo = jointControls.find(j => j.name === jointName)
        if (jointInfo) {
          clampedAngle = Math.max(jointInfo.min, Math.min(jointInfo.max, angle))
        }
      }
      
      // 应用关节角度
      availableJoints.value[jointName].setJointValue(clampedAngle)
      
      // 更新UI中的值
      const jointControl = jointControls.find(j => j.name === jointName)
      if (jointControl) {
        jointControl.value = clampedAngle
      }
      
    } catch (error) {
      console.error(`设置关节 ${jointName} 角度失败:`, error)
    }
  }
}

/**
 * 调整相机视角
 */
const fitCameraToObject = (object) => {
  const boundingBox = new THREE.Box3().setFromObject(object)
  const center = boundingBox.getCenter(new THREE.Vector3())
  const size = boundingBox.getSize(new THREE.Vector3())

  const maxSize = Math.max(size.x, size.y, size.z)
  const fitHeightDistance = maxSize / (2 * Math.atan((Math.PI * camera.fov) / 360))
  const fitWidthDistance = fitHeightDistance / camera.aspect
  const distance = 1.5 * Math.max(fitHeightDistance, fitWidthDistance)

  const direction = new THREE.Vector3(0, 1, 1).normalize()
  controls.target.copy(center)
  camera.position.copy(center).add(direction.multiplyScalar(distance))
  controls.update()
}

/**
 * 动画循环
 */
const animate = () => {
  requestAnimationFrame(animate)
  controls.update()
  renderer.render(scene, camera)
}

/**
 * 窗口大小变化处理
 */
const onWindowResize = () => {
  const container = viewerContainer.value
  camera.aspect = container.clientWidth / container.clientHeight
  camera.updateProjectionMatrix()
  renderer.setSize(container.clientWidth, container.clientHeight)
}

/**
 * 清理资源
 */
const dispose = () => {
  window.removeEventListener('resize', onWindowResize)
  controls?.dispose()
  renderer?.dispose()
}

// 监听属性变化
watch(
  () => [props.basePath, props.urdfPath],
  () => {
    loadRobot()
  }
)

watch(jointControls, (newVal) => {
  emits('computedChange', newVal)
})


// 生命周期
onMounted(() => {
  initScene()
  loadRobot()
  window.addEventListener('resize', onWindowResize)
  animate()
})

onBeforeUnmount(() => {
  dispose()
})

defineExpose({
  updateJointAngle
})
</script>

<style scoped>
/* 样式部分保持不变 */
.urdf-viewer-container {
  height: 100%;
  width: 100%;

  .urdf-viewer {
    width: 100%;
    height: 100%;
    overflow: hidden;
  }
}



.loading-overlay p {
  font-size: 16px;
  color: #ecf0f1;
}
</style>