<template>
  <div
    ref="canvasContainer"
    style="width: 100%; height: 100%;"
  />
</template>

<script>
import commonMixins from 'data-room-ui/js/mixins/commonMixins'
import paramsMixins from 'data-room-ui/js/mixins/paramsMixins'
import linkageMixins from 'data-room-ui/js/mixins/linkageMixins'
import { refreshComponentMixin } from 'data-room-ui/js/mixins/refreshComponent'
import * as BABYLON from '@babylonjs/core'
import * as GUI from '@babylonjs/gui'
import '@babylonjs/loaders'

export default {
  name: 'GltfViewer',
  mixins: [paramsMixins, commonMixins, linkageMixins, refreshComponentMixin],
  props: {
    config: {
      type: Object,
      default: () => ({})
    }
  },
  data () {
    return {
      camera: null,
      house: null,
      chair: null,
      table: null,
      button: null,
      adTexture: null,
      disc: null,
      line: null,
      animationGroup: null,
      cameraAnimation: null,
      horizontalPipe: null,
      verticalPipe: null,
      elevator: null,
      originalMaterials: null
    }
  },
  mounted () {
    this.create3D()
  },
  methods: {
    create3D () {
      const canvas = document.createElement('canvas')
      this.$refs.canvasContainer.appendChild(canvas)

      const engine = new BABYLON.Engine(canvas)

      const createScene = () => {
        const scene = new BABYLON.Scene(engine)

        this.camera = new BABYLON.ArcRotateCamera('camera', 5, 1.3, 50, new BABYLON.Vector3(0, 0, 0), scene)
        this.camera.attachControl(canvas, true)

        this.camera.lowerBetaLimit = BABYLON.Tools.ToRadians(0)
        this.camera.upperBetaLimit = BABYLON.Tools.ToRadians(80)
        this.camera.lowerRadiusLimit = 15
        this.camera.upperRadiusLimit = 80

        const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(1, 1, 1), scene)
        light.diffuse = new BABYLON.Color3(1, 1, 1)

        // showAxis(scene, 15)

        const largeGroundMat = new BABYLON.StandardMaterial('largeGroundMat')
        largeGroundMat.diffuseTexture = new BABYLON.Texture(
          'https://assets.babylonjs.com/environments/valleygrass.png'
        )
        const largeGround = BABYLON.MeshBuilder.CreateGroundFromHeightMap(
          'largeGround',
          'https://assets.babylonjs.com/environments/villageheightmap.png',
          { width: 350, height: 350, subdivisions: 560, minHeight: 0, maxHeight: 10 }
        )
        largeGround.material = largeGroundMat
        largeGround.position.y = -0.01
        largeGround.material.freeze()

        const skybox = BABYLON.MeshBuilder.CreateBox('skybox', { size: 300 })
        const skyboxMat = new BABYLON.StandardMaterial('skyboxMat')
        skyboxMat.backFaceCulling = false
        skyboxMat.reflectionTexture = new BABYLON.CubeTexture(
          'https://playground.babylonjs.com/textures/skybox',
          scene
        )
        skyboxMat.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE
        skyboxMat.diffuseColor = new BABYLON.Color3(0, 0, 0)
        skyboxMat.specularColor = new BABYLON.Color3(0, 0, 0)

        skybox.material = skyboxMat
        skybox.material.freeze()

        BABYLON.SceneLoader.ImportMeshAsync('', '/static/models/', '别墅.glb', scene).then((result) => {
          this.house = result.meshes
          this.originalMaterials = result.meshes.map(mesh => mesh.material)

          const plane = BABYLON.MeshBuilder.CreatePlane('planeEnter', { size: 1 })
          plane.parent = result.meshes[0]
          plane.position.y = 3
          plane.position.z = 9.5
          plane.position.x = -0.5

          const advancedTexture = GUI.AdvancedDynamicTexture.CreateForMesh(plane, 128, 128, false)
          advancedTexture.renderScale = 1

          this.button = GUI.Button.CreateSimpleButton('button', '进入房间')
          this.button.width = 1
          this.button.height = 0.5
          this.button.color = 'white'
          this.button.background = 'green'

          advancedTexture.addControl(this.button)

          const LogoPlane = BABYLON.MeshBuilder.CreatePlane('logo', { width: 3, height: 1.5 }, scene)
          LogoPlane.rotation.y = Math.PI / 2
          LogoPlane.position.x = 5.9
          LogoPlane.position.y = 2
          LogoPlane.position.z = 1

          const LogoMaterial = new BABYLON.StandardMaterial('logoMaterial', scene)
          LogoMaterial.diffuseTexture = new BABYLON.Texture('/static/images/gwise.png', scene)
          LogoMaterial.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5)
          LogoPlane.material = LogoMaterial
        })

        BABYLON.SceneLoader.ImportMeshAsync('', '/static/models/', '地基.glb', scene).then((result) => {
          result.meshes.forEach((mesh) => {
            mesh.material.freeze()
          })
        })

        BABYLON.SceneLoader.ImportMeshAsync('', '/static/models/', 'chair.glb', scene).then((result) => {
          this.chair = result.meshes
          this.chair[0].position.x = 1.5

          this.chair.forEach((mesh) => {
            if (mesh.name !== '__root__') {
              mesh.parent = this.chair[0]
            }
            mesh.name = 'chair'
            mesh.rotation.y = Math.PI / 3.6

            mesh.occlusionQueryAlgorithmType = BABYLON.AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE
            mesh.occlusionRetryCount = -1
            mesh.isOccluded = true
          })

          this.createAnimation(this.chair[0])

          const LinePoints = [
            new BABYLON.Vector3(0, 0.5, 0),
            new BABYLON.Vector3(0, 1.5, 0)
          ]

          this.line = BABYLON.MeshBuilder.CreateDashedLines('dashedLine', {
            points: LinePoints,
            dashSize: 0.5,
            gapSize: 0.2,
            dashNb: 20
          }, scene)

          this.line.parent = this.chair[0]

          this.disc = BABYLON.MeshBuilder.CreateDisc('circle', { radius: 0.3, tessellation: 60 }, scene)
          this.disc.parent = this.chair[0]
          this.disc.position.y = 1.6
          this.disc.rotation.x = Math.PI

          const advancedTexture = GUI.AdvancedDynamicTexture.CreateForMesh(this.disc, 128, 128, false)
          advancedTexture.renderScale = 1

          const textBlock = new GUI.TextBlock()
          textBlock.text = '点击椅子'
          textBlock.color = 'white'
          textBlock.fontSize = 16
          textBlock.fontWeight = '800'

          advancedTexture.addControl(textBlock)
        })

        BABYLON.SceneLoader.ImportMeshAsync('', '/static/models/', 'table.glb', scene).then((result) => {
          this.table = result.meshes

          this.table[0].position.x = -1
          this.table[0].scaling = new BABYLON.Vector3(1.4, 1.4, 1.4)
        })

        this.elevator = BABYLON.MeshBuilder.CreateBox('elevator', { width: 2, height: 4, depth: 2 }, scene)
        this.elevator.position.x = 5.2
        this.elevator.position.y = 2
        this.elevator.position.z = -3.5

        // 高亮电梯（发光材质）
        const highlightMaterial = new BABYLON.StandardMaterial('highlight', scene)
        highlightMaterial.emissiveColor = new BABYLON.Color3(1, 1, 0) // 黄色发光
        this.elevator.material = highlightMaterial

        // 为电梯创建上下移动动画
        const elevatorAnimation = new BABYLON.Animation(
          'elevatorAnimation',
          'position.y',
          30,
          BABYLON.Animation.ANIMATIONTYPE_FLOAT,
          BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
        )

        const elevatorKeys = [
          { frame: 0, value: 2 },
          { frame: 50, value: 2 },
          { frame: 150, value: 6 },
          { frame: 200, value: 6 },
          { frame: 300, value: 2 }
        ]

        elevatorAnimation.setKeys(elevatorKeys)
        this.elevator.animations = [elevatorAnimation]
        this.elevator.isVisible = false

        scene.beginAnimation(this.elevator, 0, 300, true)

        this.createGlowPipe(scene)

        return scene
      }

      this.createAnimation = (mesh) => {
        // 创建动画并作用于position属性
        const positionAnimation = new BABYLON.Animation('move', 'position', 30,
          BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)

        // 定义关键帧
        let Keys = [
          { frame: 0, value: new BABYLON.Vector3(1.5, 0, 0) },
          { frame: 20, value: new BABYLON.Vector3(1, 0, -1) },
          { frame: 40, value: new BABYLON.Vector3(-0.5, 0, -1.5) },
          { frame: 60, value: new BABYLON.Vector3(-0.6, 0, -0.8) }
        ]
        positionAnimation.setKeys(Keys)

        const rotationAnimation = new BABYLON.Animation('rotation', 'rotation', 30,
          BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)

        Keys = [
          { frame: 0, value: new BABYLON.Vector3(0, Math.PI, 0) },
          { frame: 20, value: new BABYLON.Vector3(0, Math.PI + Math.PI / 10, 0) },
          { frame: 40, value: new BABYLON.Vector3(0, Math.PI + Math.PI / 5, 0) },
          { frame: 60, value: new BABYLON.Vector3(0, Math.PI + Math.PI / 3.6) }
        ]
        rotationAnimation.setKeys(Keys)

        this.animationGroup = new BABYLON.AnimationGroup('Animation Group')
        this.animationGroup.addTargetedAnimation(positionAnimation, mesh)
        this.animationGroup.addTargetedAnimation(rotationAnimation, mesh)

        this.animationGroup.normalize(0, 60)
        this.animationGroup.speedRatio = 0.5

        const plane = BABYLON.MeshBuilder.CreatePlane('planeExit', { size: 0.3 })
        plane.parent = this.table[0]
        plane.position.y = 1
        plane.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL

        const advancedTexture = GUI.AdvancedDynamicTexture.CreateForMesh(plane, 128, 128, false)
        advancedTexture.renderScale = 1

        const button = GUI.Button.CreateSimpleButton('button', '离开房间')
        button.width = 1
        button.height = 0.5
        button.color = 'white'
        button.background = 'green'

        this.cameraAnimation = new BABYLON.Animation('cameraAnimation', 'radius', 30,
          BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT)

        advancedTexture.addControl(button)
      }

      // 创建场景
      const scene = createScene()
      // 注册一个渲染循环，以便在每一帧都渲染场景
      engine.runRenderLoop(function () {
        scene.render()
      })

      this.createUI(scene)

      canvas.addEventListener('pointerup', (event) => {
        const rect = canvas.getBoundingClientRect()

        const correctedMouseX = (event.clientX - rect.left) * (canvas.width / rect.width)
        const correctedMouseY = (event.clientY - rect.top) * (canvas.height / rect.height)

        // 进行拾取
        const pickResult = scene.pick(correctedMouseX, correctedMouseY)
        if (pickResult.hit) {
          const pickedMesh = pickResult.pickedMesh
          if (pickedMesh.name === 'planeEnter') {
            const Keys = [
              { frame: 0, value: this.camera.radius },
              { frame: 60, value: 6.5 }
            ]
            this.cameraAnimation.setKeys(Keys)
            this.camera.animations = []
            this.camera.animations.push(this.cameraAnimation)
            this.camera.lowerRadiusLimit = 3

            scene.beginAnimation(this.camera, 0, 60, false, 0.6, () => {
              this.camera.upperRadiusLimit = 6.8
            })
          }

          if (pickedMesh.name === 'planeExit') {
            const Keys = [
              {
                frame: 0,
                value: this.camera.radius
              },
              {
                frame: 60,
                value: 50
              }
            ]
            this.cameraAnimation.setKeys(Keys)
            this.camera.animations = []
            this.camera.animations.push(this.cameraAnimation)
            this.camera.upperRadiusLimit = 60

            scene.beginAnimation(this.camera, 0, 60, false, 0.6, () => {
              this.camera.lowerRadiusLimit = 15
            })
          }

          if (pickedMesh.name === 'chair') {
            this.animationGroup.play(false)
          }
        }
      })

      // 监听窗口大小变化，调整引擎的大小
      window.addEventListener('resize', () => {
        engine.resize()
      })
    },
    renderHouse (type) {
      if (type === 0) {
        // 创建半透明材质
        const semiTransparentMaterial = new BABYLON.StandardMaterial('semiTransparent', this.scene)
        semiTransparentMaterial.diffuseColor = new BABYLON.Color3(0.5, 0.7, 1)
        semiTransparentMaterial.alpha = 0.3

        this.house.forEach((mesh) => {
          // 为每个网格设置半透明材质
          mesh.material = semiTransparentMaterial
          mesh.renderingGroupId = 0

          // 启用边缘渲染
          mesh.enableEdgesRendering()
          mesh.edgesWidth = 1.0
          mesh.edgesColor = new BABYLON.Color4(0, 1, 1, 1)
        })
      } else {
        this.house.forEach((mesh, index) => {
          mesh.material = this.originalMaterials[index]
          mesh.disableEdgesRendering()
        })
      }
    },
    createGlowPipe (scene) {
      // 创建水平段管道
      this.horizontalPipe = BABYLON.MeshBuilder.CreateCylinder('horizontalPipe', {
        diameter: 0.15,
        height: 18.5,
        tessellation: 32
      }, scene)

      this.horizontalPipe.position.x = -7.3
      this.horizontalPipe.position.z = 0.25

      // 创建材质
      const pipeMaterial = new BABYLON.StandardMaterial('pipeMaterial', scene)
      pipeMaterial.alpha = 1

      // 创建黄白相间的纹理
      const pipeTexture = new BABYLON.DynamicTexture('dynamicTexture', { width: 512, height: 512 }, scene, false)
      const context = pipeTexture.getContext()

      // 绘制黄白相间的条纹
      const stripeHeight = 64
      for (let i = 0; i < 512 / stripeHeight; i++) {
        context.fillStyle = i % 2 === 0 ? 'green' : 'white'
        context.fillRect(0, i * stripeHeight, 512, stripeHeight)
      }

      // 更新纹理
      pipeTexture.update()

      // 设置纹理重复模式，避免开头出现空白
      pipeTexture.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE
      pipeTexture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE

      // 将纹理应用到材质上
      pipeMaterial.diffuseTexture = pipeTexture

      // 将材质应用到水平管道上
      this.horizontalPipe.material = pipeMaterial

      // 添加发光效果
      const glowLayer = new BABYLON.HighlightLayer('glowLayer', scene)
      glowLayer.addMesh(this.horizontalPipe, BABYLON.Color3.Green())

      // 增加自发光的强度
      glowLayer.intensity = 5

      // 设置水平段管道的旋转，使其沿 z 轴方向躺下
      this.horizontalPipe.rotation.x = Math.PI / 2
      this.horizontalPipe.position.y = 0.09 // 设置 y 轴高度为 0.1

      // 创建垂直段管道
      this.verticalPipe = BABYLON.MeshBuilder.CreateCylinder('verticalPipe', {
        diameter: 0.15,
        height: 10,
        tessellation: 32
      }, scene)

      // 将材质应用到垂直管道上
      this.verticalPipe.material = pipeMaterial

      // 设置垂直段管道的旋转，使其沿 y 轴方向竖直
      this.verticalPipe.rotation.x = 0 // 保持竖直方向
      this.verticalPipe.position.y = 5.09 // 设置垂直段的起始位置，使它与水平段末端相接
      this.verticalPipe.position.z = 9.4 // 调整 z 轴位置，使两段对接
      this.verticalPipe.position.x = -7.3 // 调整 x 轴位置，使两段对接

      // 添加发光效果到垂直段管道
      glowLayer.addMesh(this.verticalPipe, BABYLON.Color3.Green())

      this.horizontalPipe.isVisible = false
      this.verticalPipe.isVisible = false

      // 实现水平段纹理移动的动画效果，减慢速度5倍
      scene.registerBeforeRender(function () {
        const offset = performance.now() * 0.001 / 5
        pipeMaterial.diffuseTexture.vOffset = offset % 1
      })
    },
    createUI (scene) {
      // 创建一个div1容器
      const container1 = document.createElement('div')
      container1.style.position = 'fixed'
      container1.style.left = '55.2%'
      container1.style.top = '96%'
      container1.style.transform = 'translateX(-50%)'
      container1.style.zIndex = '9999'
      container1.style.display = 'flex'
      container1.style.alignItems = 'center'
      container1.style.justifyContent = 'center'

      const checkbox1 = document.createElement('input')
      checkbox1.type = 'checkbox'
      checkbox1.setAttribute('id', 'cbox')
      checkbox1.style.width = '20px'
      checkbox1.style.height = '20px'
      checkbox1.style.color = 'black'

      const label1 = document.createElement('label')
      label1.textContent = '显示电梯'
      label1.setAttribute('for', 'cbox')
      label1.style.color = 'white'
      label1.style.fontSize = '18px'
      label1.style.marginLeft = '5px'

      container1.appendChild(checkbox1)
      container1.appendChild(label1)

      checkbox1.addEventListener('change', () => {
        if (checkbox1.checked) {
          this.elevator.isVisible = true
        } else {
          this.elevator.isVisible = false
        }
      })

      document.getElementById('canvas-container').appendChild(container1)
      container1.style.visibility = 'hidden'

      // 创建一个div2容器
      const container2 = document.createElement('div')
      container2.style.position = 'fixed'
      container2.style.left = '60.6%'
      container2.style.top = '96%'
      container2.style.transform = 'translateX(-50%)'
      container2.style.zIndex = '9999'
      container2.style.display = 'flex'
      container2.style.alignItems = 'center'
      container2.style.justifyContent = 'center'

      const checkbox2 = document.createElement('input')
      checkbox2.type = 'checkbox'
      checkbox2.setAttribute('id', 'cbox')
      checkbox2.style.width = '20px'
      checkbox2.style.height = '20px'
      checkbox2.style.color = 'black'

      const label2 = document.createElement('label')
      label2.textContent = '显示管道'
      label2.setAttribute('for', 'cbox')
      label2.style.color = 'white'
      label2.style.fontSize = '18px'
      label2.style.marginLeft = '5px'

      container2.appendChild(checkbox2)
      container2.appendChild(label2)

      checkbox2.addEventListener('change', () => {
        if (checkbox2.checked) {
          this.horizontalPipe.isVisible = true
          this.verticalPipe.isVisible = true
        } else {
          this.horizontalPipe.isVisible = false
          this.verticalPipe.isVisible = false
        }
      })

      document.getElementById('canvas-container').appendChild(container2)
      container2.style.visibility = 'hidden'

      // 创建一个div容器
      const container = document.createElement('div')
      container.style.position = 'fixed'
      container.style.left = '50%'
      container.style.top = '96%'
      container.style.transform = 'translateX(-50%)'
      container.style.zIndex = '9999'
      container.style.display = 'flex'
      container.style.alignItems = 'center'
      container.style.justifyContent = 'center'

      const checkbox = document.createElement('input')
      checkbox.type = 'checkbox'
      checkbox.setAttribute('id', 'cbox')
      checkbox.style.width = '20px'
      checkbox.style.height = '20px'
      checkbox.style.color = 'black'

      const label = document.createElement('label')
      label.textContent = ' 科技感'
      label.setAttribute('for', 'cbox')
      label.style.color = 'white'
      label.style.fontSize = '18px'
      label.style.marginLeft = '5px'

      container.appendChild(checkbox)
      container.appendChild(label)

      checkbox.addEventListener('change', () => {
        if (checkbox.checked) {
          this.renderHouse(0)
          this.chair.forEach((mesh) => {
            mesh.isVisible = false
          })
          this.table.forEach((mesh) => {
            mesh.isVisible = false
          })
          this.line.isVisible = false
          this.disc.isVisible = false

          container1.style.visibility = 'visible'
          container2.style.visibility = 'visible'
        } else {
          this.renderHouse(1)
          this.chair.forEach((mesh) => {
            mesh.isVisible = true
          })
          this.table.forEach((mesh) => {
            mesh.isVisible = true
          })
          this.line.isVisible = true
          this.disc.isVisible = true

          container1.style.visibility = 'hidden'
          container2.style.visibility = 'hidden'
        }
      })

      document.getElementById('canvas-container').appendChild(container)
    }
  }
}
</script>

<style>
canvas {
  width: 100%;
  height: 100%;
}
</style>
