<template>
  <div class="canvas-container" ref="canvasContainer" tabindex="1" />
</template>
<script setup lang="ts">
import * as THREE from 'three'
import $ from 'jquery'
import Stats from 'three/examples/jsm/libs/stats.module'
import {
  ref,
  onMounted,
  nextTick,
  reactive,
  watch,
  getCurrentInstance,
  onUnmounted,
  onBeforeUnmount,
  defineExpose
} from 'vue'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

// DOM refs
const canvasContainer = ref(null)

// 窗口大小关联
let resizeObserver

// Three.js 场景相关
let scene, camera, renderer, controls
let statsControls, axesHelper, gridHelper

const state = designer.editorState

function initMode2DCamera() {
  if (camera) {
    scene.remove(camera)
  }

  // ============================ 创建正交相机
  const viewerDom = canvasContainer.value
  const cameraNew = new THREE.OrthographicCamera(
    viewerDom.clientWidth / -2,
    viewerDom.clientWidth / 2,
    viewerDom.clientHeight / 2,
    viewerDom.clientHeight / -2,
    1,
    500
  )
  cameraNew.position.set(0, 100, 0)
  cameraNew.lookAt(0, 0, 0)
  cameraNew.zoom = 30
  camera = cameraNew
  scene.add(camera)

  // ============================ 创建控制器
  const controlsNew = new OrbitControls(
    camera,
    renderer.domElement
  )
  controlsNew.enableDamping = false
  controlsNew.enableZoom = true
  controlsNew.enableRotate = false
  controlsNew.mouseButtons = { LEFT: THREE.MOUSE.PAN } // 鼠标中键平移
  controlsNew.screenSpacePanning = false // 定义平移时如何平移相机的位置 控制不上下移动
  controlsNew.listenToKeyEvents(viewerDom) // 监听键盘事件
  controlsNew.keys = { LEFT: 'KeyA', UP: 'KeyW', RIGHT: 'KeyD', BOTTOM: 'KeyS' }
  controlsNew.panSpeed = 1
  controlsNew.keyPanSpeed = 20 // normal 7
  controlsNew.minDistance = 0.1
  controlsNew.maxDistance = 1000
  controls = controlsNew
  controlsNew.addEventListener('change', syncCameraState)

  camera.updateProjectionMatrix()

  syncCameraState()
}

function initThree() {
  const viewerDom = canvasContainer.value

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

  // 渲染器
  renderer = new THREE.WebGLRenderer({
    logarithmicDepthBuffer: true,
    antialias: true,
    alpha: true,
    precision: 'mediump',
    premultipliedAlpha: true,
    preserveDrawingBuffer: false,
    powerPreference: 'high-performance'
  })
  renderer.outputEncoding = THREE.SRGBColorSpace
  renderer.clearDepth()
  renderer.shadowMap.enabled = true
  renderer.toneMapping = THREE.ACESFilmicToneMapping
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(viewerDom.getBoundingClientRect().width, viewerDom.getBoundingClientRect().height)
  viewerDom.appendChild(renderer.domElement)

  // 创建正交摄像机
  initMode2DCamera()

  // 辅助线
  axesHelper = new THREE.AxesHelper(5)
  scene.add(axesHelper)

  gridHelper = new THREE.GridHelper(500, 500)
  gridHelper.material = new THREE.LineBasicMaterial({
    color: 0x888888,
    opacity: 1,
    transparent: true
  })

  scene.add(gridHelper)

  // 光照
  const ambientLight = new THREE.AmbientLight(0xffffff, 1.5)
  scene.add(ambientLight)

  const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5)
  directionalLight.position.set(5, 5, 5).multiplyScalar(3)
  directionalLight.castShadow = true
  scene.add(directionalLight)

  const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1)
  scene.add(hemisphereLight)

  // 性能监控
  statsControls = new Stats()
  statsControls.showPanel(0)
  statsControls.dom.style.position = 'absolute'
  statsControls.dom.style.top = '2px'
  statsControls.dom.style.left = '0'
  viewerDom.appendChild(statsControls.dom)
  $(statsControls.dom).children().css('height', '28px')

  // 创建几何体和材质
  const geometry = new THREE.BoxGeometry(1, 1, 1)
  const material = new THREE.MeshStandardMaterial({
    color: 0xcccccc,
    metalness: 0.9,
    roughness: 0.1
  })

  const cube = new THREE.Mesh(geometry, material)
  scene.add(cube)
  camera.position.z = 5

  animate()
}

// 动画循环
function animate() {
  requestAnimationFrame(animate)
  renderView()
}

function renderView() {
  statsControls?.update()
  renderer?.render(scene, camera)
}

onMounted(() => {
  const editor = getCurrentInstance()
  nextTick(() => {
    initThree()

    const viewerDom = canvasContainer.value
    if (resizeObserver) {
      resizeObserver.unobserve(viewerDom)
    }
    resizeObserver = new ResizeObserver(handleResize)
    resizeObserver.observe(viewerDom)

    state.ready = true

    window['editor'] = editor
    window['renderer'] = renderer
    window['scene'] = scene
    window['camera'] = camera
    window['renderer'] = renderer
    window['controls'] = controls

    viewerDom?.focus()
  })
})

onBeforeUnmount(() => {
  state.ready = false

  cleanupThree()

  const viewerDom = canvasContainer.value
  if (resizeObserver) {
    resizeObserver.unobserve(viewerDom)
  }

  delete window['editor']
  delete window['renderer']
  delete window['scene']
  delete window['camera']
  delete window['renderer']
  delete window['controls']
})


function handleResize(entries) {
  for (let entry of entries) {
    // entry.contentRect包含了元素的尺寸信息
    console.log('Element size changed:', entry.contentRect)

    const width = entry.contentRect.width
    const height = entry.contentRect.height

    if (camera instanceof THREE.PerspectiveCamera) {
      camera.aspect = width / height
      camera.updateProjectionMatrix()

    } else if (camera instanceof THREE.OrthographicCamera) {
      camera.left = width / -2
      camera.right = width / 2
      camera.top = height / 2
      camera.bottom = height / -2
      camera.updateProjectionMatrix()
    }
    renderer.setSize(width, height)
    break
  }
}

watch(() => state.camera.position.y, (newVal) => {
  if (state.ready) {
    updateGridVisibility()
  }
}, { deep: true })

/**
 * 根据可视化范围更新网格的透明度
 */
function updateGridVisibility() {
  const cameraDistance = state.camera.position.y
  const maxVisibleDistance = 60 // 网格完全可见的最大距离
  const fadeStartDistance = 10  // 开始淡出的距离

  // 计算透明度（0~1）
  let opacity = 1
  if (cameraDistance > fadeStartDistance) {
    opacity = 1 - Math.min((cameraDistance - fadeStartDistance) / (maxVisibleDistance - fadeStartDistance), 1)
  }

  // 修改网格材质透明度
  gridHelper.material.opacity = opacity
  gridHelper.material.transparent = opacity < 1
  console.log('opacity', opacity)
}

function cleanupThree() {
  // 移除旧模型
  if (scene) {
    scene.traverse((obj) => {
      // 释放几何体
      if (obj.geometry) {
        obj.geometry.dispose()
      }

      // 释放材质
      if (obj.material) {
        if (Array.isArray(obj.material)) {
          obj.material.forEach(m => m.dispose())
        } else {
          obj.material.dispose()
        }
      }

      // 释放纹理
      if (obj.texture) {
        obj.texture.dispose()
      }

      // 释放渲染目标
      if (obj.renderTarget) {
        obj.renderTarget.dispose()
      }

      // 移除事件监听（如 OrbitControls）
      if (obj.dispose) {
        obj.dispose()
      }
    })

    // 清空场景
    scene.children = []
  }

  if (statsControls) {
    statsControls.dom.remove()
  }

  if (renderer) {
    renderer.dispose()
    renderer.forceContextLoss()
    console.log('WebGL disposed, memory:', renderer.info.memory)
    renderer.domElement = null
  }
}

function getEffectiveViewDistance() {
  // 1. 获取相机到目标的距离
  const targetDistance = controls.target.distanceTo(camera.position)

  // 2. 计算当前视口高度（世界单位）
  const viewHeight = (camera.top - camera.bottom) / camera.zoom

  // 3. 计算等效的透视相机距离
  // 假设我们希望匹配一个虚拟的透视相机（通常使用45度fov作为参考）
  const referenceFOV = 45 // 参考视场角
  return viewHeight / (2 * Math.tan(THREE.MathUtils.degToRad(referenceFOV) / 2))
}

function syncCameraState() {
  if (camera) {
    state.camera.position.x = camera.position.x
    state.camera.position.y = getEffectiveViewDistance()
    state.camera.position.z = camera.position.z
  }
}
</script>