import { ca } from "element-plus/es/locales.mjs";
import {
  BoxGeometry,
  EquirectangularReflectionMapping,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  Raycaster,
  Scene,
  SphereGeometry,
  SRGBColorSpace,
  Texture,
  TextureLoader,
  Vector2,
  Matrix4,
  WebGLRenderer,
  LoadingManager,
  CubeTexture,
  CubeTextureLoader,
} from "three";
import { OrbitControls } from "three/examples/jsm/Addons.js";

export const init = (canvas: HTMLCanvasElement) => {
  const manager = new LoadingManager()
  const texLoader = new TextureLoader(manager);
  const cubeLoader = new CubeTextureLoader(manager)
  const scene = new Scene();
  const camera = new PerspectiveCamera(70, 1, 1, 8000);
  const rang = 4000;

  const controls = new OrbitControls(camera, canvas.parentElement);
  controls.target.set(0, 0, 0)
  controls.enableDamping = true;
  controls.enableZoom = false;
  controls.enablePan = false;
  controls.rotateSpeed = -0.25;

  camera.position.set(0, 0, -1)

  // 处理鼠标滚轮事件以实现 zoomToCursor 效果
  function onMouseWheel(event) {
    event.preventDefault();
    const scaleFactor = 0.01;
    const delta = event.deltaY;
    camera.fov = Math.min(Math.max(30, camera.fov + scaleFactor * delta), 89)
    camera.updateProjectionMatrix()

    // // 获取当前鼠标位置
    // const mouse = new Vector2();
    // mouse.x = (event.clientX / window.innerWidth) * 2 - 1; // 转换为 [-1, 1]
    // mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 转换为 [-1, 1]

    // // 使用 Raycaster 将鼠标位置转换为场景中的坐标
    // const raycaster = new Raycaster();
    // raycaster.setFromCamera(mouse, camera);
    // const intersection = raycaster.intersectObject(cube); // 可以修改为场景中的其他对象

    // if (intersection.length > 0) {
    //   const scaleFactor = 0.1;
    //   const delta = -event.deltaY;
    //   const moveLen = delta * scaleFactor
    //   const dire = intersection[0].point.sub(camera.position).normalize()
    //   const origin = camera.position.clone()
    //   origin.add(dire.clone().multiplyScalar(moveLen))

    //   if (origin.length() < rang / 10) {
    //     const targetDire = controls.target.clone().sub(camera.position)
    //     camera.position.copy(origin)
    //     controls.target.copy(origin.add(targetDire))
    //     controls.update()
    //   }
    // }
  }

  // 监听滚轮事件
  canvas.parentElement.addEventListener("wheel", onMouseWheel, { passive: false });


  const redraw = () => {
    renderer.clear()
    controls.update();
    renderer.render(scene, camera);
  }
  
  const renderer = new WebGLRenderer({ antialias: true, canvas });
  renderer.setPixelRatio(1);
  renderer.autoClear = false
  renderer.setAnimationLoop(redraw);

  const setSize = ([w, h]: [number, number]) => {
    camera.aspect = w / h;
    camera.updateProjectionMatrix();
    renderer.setSize(w, h);
  };

  let mesh: Mesh;
  let prevMat: Matrix4
  controls.saveState()
  return {
    setSize,
    redraw,
    async getTexs(urls: string | string[]) {
      urls = Array.isArray(urls) ? urls : [urls]
      const texs: Texture[] = []
      if (urls.length === 1) {
        texs.push(texLoader.load(urls[0]))
        texs[0].mapping = EquirectangularReflectionMapping;
      } else {
        const mapper = [2, 4, 0, 5, 1, 3];
        texs.push(cubeLoader.load(mapper.map(i => urls[i])))
      }
      texs.forEach(tex => tex.colorSpace = SRGBColorSpace)
      
      await new Promise<void>((resolve, reject) => {
        manager.onLoad = resolve
        manager.onError = reject
      })
      return texs;
    },
    async changeEnv(texs: Texture[]) {
      mesh && scene.remove(mesh);
      scene.background = texs[0]
    },
    reset() {
      camera.fov = 70
      camera.updateProjectionMatrix()
      
      camera.position.applyMatrix4(prevMat.invert())
      prevMat = null
      controls.reset()
    },
    setYaw(yaw: number) {
      const mat = new Matrix4().makeRotationY(-yaw)
      if (prevMat) {
        mat.multiply(prevMat.invert())
      }
      prevMat = mat
      camera.position.applyMatrix4(mat)
      controls.update()
    },
    destory() {
      window.removeEventListener("wheel", onMouseWheel);
      renderer.dispose();
    },
  };
};
