import * as THREE from 'three';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer'
// import gsap from 'gsap';
import ResourceTracker from '/@/utils/threejs/ResourceTracker';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'



class UseThree {
  canvasContainer: HTMLCanvasElement;
  CSSCanvasContainer: HTMLCanvasElement | null = null;
  camera: THREE.PerspectiveCamera | null = null;
  scene: THREE.Scene | null = null;
  renderer: THREE.WebGLRenderer | null = null;
  css3dRender: CSS3DRenderer | null = null;
  orbitControls: OrbitControls | null = null;
  giftLoader: THREE.Object3D | null = null;
  animationMixer: THREE.AnimationMixer | null = null;
  animationAction: THREE.AnimationAction | null = null;
  clock: THREE.Clock = new THREE.Clock(); // 计时器
  timeoutId: NodeJS.Timeout | null = null;
  animationId: number = 0
  resourceTracker:ResourceTracker | null = null
  track: any = null
  spriteText: THREE.Sprite | null = null

  constructor(canvasSelector, cssCanvas?) {
 

    this.resourceTracker = new ResourceTracker()
    this.track = this.resourceTracker.track.bind(this.resourceTracker)
    this.animationId = 0
    this.canvasContainer = document.querySelector(canvasSelector);

    //初始化
    this.init(cssCanvas);
    this.animate();
    window.addEventListener('resize', this.resizeRenderer.bind(this));
    // 添加滚动事件，鼠标滚动模型执行动画
    // window.addEventListener('wheel', this.wheelRenderer.bind(this));
  }
  init(cssCanvas?) {
    // 初始化场景
    this.initScene();
    // 初始化环境光
    this.initLight();
    // 初始化相机
    this.initCamera();
    //初始化渲染器
    this.initRenderer();

    // 初始化控制器
    this.initControles();

    if(cssCanvas){
      this.initCSSRenderer(cssCanvas)
      // this.addTextSprite()
    }
    // this.setTestPlane()
  }

  initScene() {
    this.scene = this.track(new THREE.Scene());
    // const axesHelper = new THREE.AxesHelper(100);
    // this.scene?.add(axesHelper);

    // const size = 1000;
    // const divisions = 10;
    // const gridHelper = new THREE.GridHelper( size, divisions );
    // this.scene?.add( gridHelper )
  }

  initLight() {
    const light = this.track(new THREE.AmbientLight(0xffffff, 1));
    light.position.set(0, 1000, 1000);
    (this.scene as THREE.Scene).add(light);
  }

  initCamera() {
    this.camera = this.track(new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000));
    this.camera?.position.set(0, 0.2, 0.3);
    // const helper = new THREE.CameraHelper( this.camera);
    // this.scene?.add( helper );
    
  }

  initRenderer() {

    this.renderer = this.track(new THREE.WebGLRenderer({ antialias: true, alpha:true })) as THREE.WebGLRenderer;
    // 设置屏幕像素比
    this.renderer?.setPixelRatio(window.devicePixelRatio);
    // 设置渲染的尺寸
    this.renderer?.setSize(window.innerWidth, window.innerHeight);
    // 色调映射
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;

    this.renderer.outputEncoding = THREE.sRGBEncoding;

    this.renderer.shadowMap.enabled = true

    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap

    // 曝光程度
    this.renderer.toneMappingExposure = 1;

    this.canvasContainer.appendChild(this.renderer.domElement);
    
  }

  initCSSRenderer(cssCanvas) {
    this.CSSCanvasContainer = document.querySelector(cssCanvas);
    this.css3dRender = this.track(new CSS3DRenderer()) as CSS3DRenderer
    this.css3dRender.setSize((window.innerWidth), (window.innerHeight))
    this.CSSCanvasContainer?.appendChild(this.css3dRender.domElement)
    this.css3dRender.render(this.scene as THREE.Scene, this.camera as THREE.PerspectiveCamera)
    this.orbitControls = this.track(new OrbitControls(this.camera as THREE.Camera, this.css3dRender?.domElement)) as OrbitControls;
    this.orbitControls.update()
    // this.orbitControls.enableZoom = false;
    // // to disable rotation
    // this.orbitControls.enableRotate = false;
    // // to disable pan
    // this.orbitControls.enablePan = false;
  }

  initControles() {
    this.orbitControls = this.track(new OrbitControls(this.camera as THREE.Camera, this.renderer?.domElement)) as OrbitControls;
    this.orbitControls.update()
    // this.orbitControls.enableZoom = false;
    // // to disable rotation
    // this.orbitControls.enableRotate = false;
    // // to disable pan
    // this.orbitControls.enablePan = false;
  }

  setModalCenter(group) {
    var box3 = new THREE.Box3()
  
    // 计算层级模型group的包围盒
    // 模型group是加载一个三维模型返回的对象，包含多个网格模型
    box3.expandByObject(group)
    // 计算一个层级模型对应包围盒的几何体中心在世界坐标中的位置
    var center = new THREE.Vector3()
    box3.getCenter(center)
    // console.log('查看几何体中心坐标', center);
    // 重新设置模型的位置，使之居中。
    group.position.x = group.position.x - center.x
    group.position.y = group.position.y - center.y
    group.position.z = group.position.z - center.z
  };

  setModel(modalName) {
    const a = new Date().getTime() / 1000
    return new Promise(async (resolve, reject) => {
      try {
        const db =  window['CustomDB']
        const modalArr =  await db.modal.where('modalName').equals(modalName).toArray()
        // debugger
        if(modalArr.length > 0) {
          const modalValue = modalArr[0].modalVal
          try {
            const gltfLoader = new GLTFLoader()
            const dracoLoader = new DRACOLoader();
            dracoLoader.setDecoderPath( '/3D/draco/gltf/' );
            dracoLoader.setDecoderConfig({ type: "js" }); //使用兼容性强的draco_decoder.js解码器
            dracoLoader.preload();
            gltfLoader.setDRACOLoader(dracoLoader);

            gltfLoader.setPath('/3d/glft/')
            gltfLoader.parse(modalValue, '/3d/glft/', (gltf) => {
              const object = this.track(gltf.scene.children[0])
              this.setModalCenter(object)
              object.traverse((obj) => {
                if (obj instanceof THREE.Mesh) {
                  obj.material.emissiveIntensity = 1
                  obj.material.emissiveMap = obj.material.map
                  if(obj.name !== "buxiugangse") {
                    obj.receiveShadow = true
                  }
                  obj.castShadow = true
                  
                  
                } else if (obj.type === 'Object3D') {
                  // const text3D = this.addYFText(obj)
                  // const textCQ3D = this.addCQText(obj)
                  // gltf.scene.add(text3D)
                  // gltf.scene.add(textCQ3D)
                }
              })
              this.scene?.add(object);
              console.log(object);
              resolve(object)
            }, (err)=> {
              console.log(err);
              
            })
  
          } catch (error) {
            console.log(error);
          }
        } 
      } catch (error) {
        reject('加载模型出错')
      }
    })
  }

  setTestPlane() {
			const plane = new THREE.Mesh(
				new THREE.PlaneGeometry( 100, 100 ),
				new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
			);
			plane.rotation.x = - Math.PI / 2;
			plane.position.y = 0.03;
			plane.receiveShadow = true;
			// this.scene?.add( plane );
  }
  
  /* 自定义材质 */
  setCustomMaterial(group){}

  /* 场景环境背景 */
  setEnvMap(hdr) {
    // new RGBELoader().setPath('/public/3D/hdr/').load(hdr + '.jpeg', (texture) => {
    //   debugger
    //   texture.mapping = THREE.EquirectangularReflectionMapping;
    //   (this.scene as THREE.Scene).background = texture;
    //   (this.scene as THREE.Scene).environment = texture;
    // });
    new THREE.TextureLoader().setPath('/3D/hdr/').load(hdr + '.jpeg', (texture) => {
      texture.mapping = THREE.EquirectangularReflectionMapping;
      // (this.scene as THREE.Scene).background = new THREE.Color('#00000000');
      (this.scene as THREE.Scene).environment = texture;
    });
  }

  render() {
    const delta = this.clock.getElapsedTime();
    this.resetLookAt()
    this.startMY()
    this.renderer?.render(this.scene as THREE.Object3D, this.camera as THREE.Camera);
    this.css3dRender?.render(this.scene as THREE.Scene, this.camera as THREE.PerspectiveCamera)
    this.animationMixer?.update(delta);
  }

  /* 实时物体刷新朝向 */
  resetLookAt() {
  }
  /* 漫游 */
  startMY() {}

  animate() {
    // this.renderer?.setAnimationLoop(this.render.bind(this));
    if(this.animationId != -1) {
      this.render()
      this.animationId = requestAnimationFrame(this.animate.bind(this))
    }
  }
  resizeRenderer() {
    // 更新相机比例
    (this.camera as THREE.PerspectiveCamera).aspect = window.innerWidth / window.innerHeight;
    // 刷新相机矩阵
    this.camera?.updateProjectionMatrix();
    // 设置场景尺寸
    this.renderer?.setSize(window.innerWidth, window.innerHeight);
    this.css3dRender?.setSize(window.innerWidth, window.innerHeight);
  }
  wheelRenderer(e: WheelEvent) {
    const timeScale = e.deltaY > 0 ? 1 : -1;
    this.animationAction?.setEffectiveTimeScale(timeScale);
    (this.animationAction as THREE.AnimationAction).paused = false;
    this.animationAction?.play();
    if (this.timeoutId) {
      clearTimeout(this.timeoutId);
    }
    this.timeoutId = setTimeout(() => {
      this.animationAction?.halt(0.5);
    }, 500);
  }
  deleteModal() {
    try {
      
      this.resourceTracker && this.resourceTracker.dispose()
      this.renderer?.dispose()
      this.renderer?.forceContextLoss()
      // this.renderer?.domElement = null
      this.renderer = null

      // this.css3dRender?.domElement = null
      this.css3dRender = null;

      cancelAnimationFrame(this.animationId);

      const gl = this.renderer?.domElement.getContext("webgl");
      gl && gl?.getExtension("WEBGL_lose_context")?.loseContext();

      const gl1 = this.css3dRender?.domElement.getContext("webgl");
      gl1 && gl1?.getExtension("WEBGL_lose_context")?.loseContext();

      this.animationId = -1

      this.resourceTracker?.untrack(this.resourceTracker.resources)
      // this.scene = null
      console.log('销毁场景',this.scene);
      
    } catch (error) {
      console.log(error);
    }
    // this.scene?.children.forEach((obj:any) => {
    //   if(obj.type === 'Group'){
    //     obj.traverse(function(item:any) {
    //       if (item.type === 'Mesh') {
    //         item.geometry.dispose();
    //         item.material.dispose();
    //         !!item.clear&&item.clear();
    //       }
    //     })
    //   }else if (obj.material) {
    //     obj.material.dispose();
    //   }else if (obj.geometry) {
    //     obj.geometry.dispose();
    //   }
    //   this.scene?.remove(obj)
    //   !!obj.clear??obj.clear()
    //   obj = null;
    // })
    // let gl = this.renderer?.domElement.getContext("webgl");
    // gl && gl?.getExtension("WEBGL_lose_context")?.loseContext();

    // this.renderer?.forceContextLoss();
    // this.renderer?.dispose();
    // this.camera = null;
    // this.orbitControls = null;
    // this.renderer.domElement = null;
    // this.renderer = null;

    // css3dRender.domElement = null;
    // css3dRender = null;
    // model3D.innerHTML = '';
    // css3D.innerHTML = '';
    // model3D = null
    // css3D = null

    // this.stats = null
    // scene = null

    THREE.Cache.clear();  
    console.log('3D环境已清理干净');
  }


  /* 创建字体精灵 */
  addTextSprite(message, parameters) {
    if (parameters === undefined) parameters = {};

    var fontface = parameters.hasOwnProperty("fontface") ?
        parameters["fontface"] : "Arial";

    /* 字体大小 */
    var fontsize = parameters.hasOwnProperty("fontsize") ?
        parameters["fontsize"] : 18;

    /* 边框厚度 */
    var borderThickness = parameters.hasOwnProperty("borderThickness") ?
        parameters["borderThickness"] : 4;

    /* 边框颜色 */
    var borderColor = parameters.hasOwnProperty("borderColor") ?
        parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 };

    /* 背景颜色 */
    var backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
        parameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 };

    /* 创建画布 */
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d') as CanvasRenderingContext2D;
    // canvas.width = 0
    // canvas.height = 200

    /* 字体加粗 */
    context.font = "Bold " + fontsize + "px " + fontface;

    /* 获取文字的大小数据，高度取决于文字的大小 */
    var metrics = context.measureText(message);
    var textWidth = metrics.width;

    /* 背景颜色 */
    context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
        + backgroundColor.b + "," + backgroundColor.a + ")";

    /* 边框的颜色 */
    context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
        + borderColor.b + "," + borderColor.a + ")";
    context.lineWidth = borderThickness;

    /* 绘制圆角矩形 */
    this.roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
    // this.roundRect(context, borderThickness / 2, borderThickness / 2, 10000, 10000, 6);
    /* 字体颜色 */
    context.fillStyle = "rgba(0, 0, 0, 1.0)";
    context.fillText(message, borderThickness, fontsize + borderThickness);
    // context.fillRect(borderThickness / 2, borderThickness / 2, 10000, 10000)
    /* 画布内容用于纹理贴图 */
    var texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;

    var spriteMaterial = new THREE.SpriteMaterial({ map: texture, transparent:false });
    var sprite = new THREE.Sprite(spriteMaterial);

    /* 缩放比例 */
    sprite.scale.set(10, 5, 1);

    return sprite;
  }

  /* 绘制圆角矩形 */
  roundRect(ctx, x, y, w, h, r) {

    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.lineTo(x + w - r, y);
    ctx.quadraticCurveTo(x + w, y, x + w, y + r);
    ctx.lineTo(x + w, y + h - r);
    ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
    ctx.lineTo(x + r, y + h);
    ctx.quadraticCurveTo(x, y + h, x, y + h - r);
    ctx.lineTo(x, y + r);
    ctx.quadraticCurveTo(x, y, x + r, y);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();

  }

}

export default UseThree;
