import { useThree } from '@react-three/fiber'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import * as THREE from 'three'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

function Model() {
  const groupRef = useRef<THREE.Group>(null)
  const [loadingProgress, setLoadingProgress] = useState(0)
  const [model, setModel] = useState<THREE.Group | null>(null)
  const [modelParts, setModelParts] = useState<{ [name: string]: THREE.Object3D }>({})
  const [activePart, setActivePart] = useState<string | null>(null)
  const { camera, scene } = useThree()

  const handleModelLoaded = useCallback(
    (loadedModel: THREE.Group, parts: { [name: string]: THREE.Object3D }) => {
      setModel(loadedModel)
      setModelParts(parts)
      // 初始状态下显示所有模型
      Object.values(parts).forEach(part => {
        part.visible = true
      })
      scene.add(loadedModel)
    },
    [scene]
  )

  useEffect(() => {
    const manager = new THREE.LoadingManager()
    manager.onProgress = (url, itemsLoaded, itemsTotal) => {
      setLoadingProgress((itemsLoaded / itemsTotal) * 100)
    }

    const dracoLoader = new DRACOLoader()
    dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/')
    dracoLoader.setDecoderConfig({ type: 'js' })

    const loader = new GLTFLoader(manager)
    loader.setDRACOLoader(dracoLoader)

    loader.load(
      `${serverUrl}/0/model.glb`, // 替换为你的GLB模型路径
      gltf => {
        const model = gltf.scene

        // 设置模型初始位置 (x, y, z)
        model.position.set(0, 0, 0) // 设置为场景原点

        // // 设置模型初始缩放 (x, y, z)
        model.scale.set(0.003, 0.003, 0.003) // 原始大小设

        // // 设置模型初始旋转（单位：弧度）(x, y, z)
        model.rotation.set(0, 0, 0) // 例如，不旋转。绕Y轴旋转90度可设为(0, Math.PI / 2, 0)

        model.traverse((child: any) => {
          if (child.isMesh) {
            child.castShadow = true
            child.receiveShadow = true
          }
        })

        // 3. 假设模型中的三个部分分别命名为'bs1', 'bs2', 'bs3'
        const parts: { [name: string]: THREE.Object3D } = {}
        model.children.forEach(child => {
          if (['bs1', 'bs2', 'bs3'].includes(child.name)) {
            parts[child.name] = child
          }
        })

        setModelParts(parts)
        handleModelLoaded(model, parts)
      },
      xhr => {
        // 加载进度回调已在LoadingManager中处理
      },
      error => {
        console.error('加载模型出错:', error)
      }
    )
  }, [handleModelLoaded])

  // 点击不同部位
  const focusOnPart = useCallback(
    (partName: string) => {
      if (!model || !modelParts[partName]) return

      // 隐藏所有部分，然后显示选中的部分
      Object.entries(modelParts).forEach(([name, part]) => {
        part.visible = name === partName
      })

      // 获取选中部分的包围盒并居中相机
      const bbox = new THREE.Box3().setFromObject(modelParts[partName])
      const center = bbox.getCenter(new THREE.Vector3())
      const size = bbox.getSize(new THREE.Vector3())

      // 计算相机位置，使其能够完整看到模型
      const maxDim = Math.max(size.x, size.y, size.z)
      const fov =
        camera instanceof THREE.PerspectiveCamera ? (camera.fov * Math.PI) / 180 : 0
      const cameraDistance = maxDim / (2 * Math.tan(fov / 2))

      camera.position.copy(
        center.clone().add(new THREE.Vector3(0, 0, cameraDistance * 1.5))
      )
      camera.lookAt(center)

      setActivePart(partName)
    },
    [camera, model, modelParts]
  )

  // 显示全部模型
  const showAllModels = useCallback(() => {
    if (!model) return

    // 显示所有模型部分
    Object.values(modelParts).forEach(part => {
      part.visible = true
    })

    // 将相机定位到整个模型的中心
    const bbox = new THREE.Box3().setFromObject(model)
    const center = bbox.getCenter(new THREE.Vector3())
    const size = bbox.getSize(new THREE.Vector3())

    const maxDim = Math.max(size.x, size.y, size.z)
    const fov =
      camera instanceof THREE.PerspectiveCamera ? (camera.fov * Math.PI) / 180 : 0
    const cameraDistance = maxDim / (2 * Math.tan(fov / 2))

    camera.position.copy(
      center.clone().add(new THREE.Vector3(0, 0, cameraDistance * 1.5))
    )
    camera.lookAt(center)

    setActivePart(null)
  }, [camera, model, modelParts])

  return <>{groupRef.current ? <primitive object={groupRef.current} /> : null}</>
}

const MemoModel = React.memo(Model)

export default MemoModel
