import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import Stats from 'three/examples/jsm/libs/stats.module';
import TWEEN from '@tweenjs/tween.js';
import { deepMerge, isType } from '@/utils';

export default class Earth3d {
  constructor(options = {}) {
    let defaultOptions = {
      isFull: true,
      container: null,
      width: window.innerWidth,
      height: window.innerHeight,
      bgColor: 0x0e2438, // 深蓝偏亮背景，替代纯黑以提升亮度
      materialColor: 0xff0000,
      controls: {
        visibel: true, // 是否开启
        enableDamping: true, // 阻尼
        autoRotate: false, // 自动旋转
        maxPolarAngle: Math.PI, // 相机垂直旋转角度的上限
      },
      statsVisibel: true,
      axesVisibel: true,
      axesHelperSize: 250, // 左边尺寸
    };
    this.options = deepMerge(defaultOptions, options);
    this.container = document.querySelector(this.options.container);
    
    // 确保容器尺寸有效，避免Canvas尺寸为0的错误
    this.options.width = Math.max(this.container.offsetWidth, 800);
    this.options.height = Math.max(this.container.offsetHeight, 600);
    
    // 如果容器尺寸仍然为0，使用默认值
    if (this.options.width === 0 || this.options.height === 0) {
      this.options.width = 800;
      this.options.height = 600;
    }
    this.scene = new THREE.Scene(); // 场景
    this.camera = null; // 相机
    this.renderer = null; // 渲染器
    this.mesh = null; // 网格
    this.animationStop = null; // 用于停止动画
    this.controls = null; // 轨道控制器
    this.stats = null; // 统计

    this.init();
  }
  init() {
       this.initStats();
       this.initCamera();
       this.initModel();
       this.initRenderer(); // 异步初始化，其他组件在continueInit中初始化
     }
  async initModel() {}

  /**
   * 运行
   */
  run() {
    // 如果渲染器已经准备好，直接开始循环
    if (this.renderer) {
      this.loop();
    } else {
      // 否则标记需要启动，等待渲染器创建完成
      this.shouldStart = true;
    }
  }
  // 循环
  loop() {
    // 检查渲染器是否存在
    if (!this.renderer) {
      return;
    }
    
    this.animationStop = window.requestAnimationFrame(() => {
      this.loop();
    });
    // 这里是你自己业务上需要的code
    this.renderer.render(this.scene, this.camera);
    // 控制相机旋转缩放的更新
    if (this.options.controls.visibel) this.controls.update();
    // 统计更新
    if (this.options.statsVisibel) this.stats.update();

    TWEEN.update();
  }
  initCamera() {
    let { width, height } = this.options;
    let rate = width / height;
    // 设置45°的透视相机,更符合人眼观察
    this.camera = new THREE.PerspectiveCamera(45, rate, 0.1, 1500);
    // this.camera.position.set(-428.88, 861.97, -1438.0)
    this.camera.position.set(270.27, 173.24, 257.54);
    // this.camera.position.set(-102, 205, -342)

    this.camera.lookAt(0, 0, 0);
  }
  /**
   * 初始化渲染器
   */
  initRenderer() {
    let { width, height, bgColor } = this.options;
    
    // 强制清理所有WebGL上下文
    if (this.renderer) {
      this.renderer.dispose();
      this.renderer.forceContextLoss();
      this.renderer = null;
    }
    
    // 清理容器中现有的所有子元素
    while (this.container.firstChild) {
      this.container.removeChild(this.container.firstChild);
    }
    
    // 强制垃圾回收
    if (window.gc) {
      window.gc();
    }
    
    // 延迟创建新的渲染器，确保上下文完全释放
    setTimeout(() => {
      try {
        // 重新获取容器尺寸，确保有效
        const containerWidth = this.container.offsetWidth || window.innerWidth;
        const containerHeight = this.container.offsetHeight || window.innerHeight;
        
        // 确保尺寸有效
        const validWidth = Math.max(containerWidth, 800);
        const validHeight = Math.max(containerHeight, 600);
        
        // 更新options中的尺寸
        this.options.width = validWidth;
        this.options.height = validHeight;
        
        // 创建一个新的canvas元素
        const canvas = document.createElement('canvas');
        let renderer = new THREE.WebGLRenderer({
          canvas: canvas,
          antialias: true,
          preserveDrawingBuffer: false,
          powerPreference: "high-performance"
        });
        
        // 设置canvas的分辨率
        renderer.setPixelRatio(window.devicePixelRatio);
        // 设置canvas 的尺寸大小
        renderer.setSize(validWidth, validHeight);
        // 设置背景色
        renderer.setClearColor(bgColor, 1);
        // 设置canvas的z-index，确保CSS2D渲染器在其之上
        renderer.domElement.style.zIndex = '1';
        renderer.domElement.style.position = 'absolute';
        // 插入到dom中
        this.container.appendChild(renderer.domElement);
        this.renderer = renderer;
        
        // 继续初始化其他组件
        this.continueInit();
      } catch (error) {
        console.error('WebGL渲染器创建失败:', error);
        // 创建一个错误提示
        const errorDiv = document.createElement('div');
        errorDiv.innerHTML = '3D渲染器初始化失败，请刷新页面重试';
        errorDiv.style.cssText = 'color: #ff6b6b; text-align: center; padding: 50px; font-size: 16px;';
        this.container.appendChild(errorDiv);
      }
    }, 100);
  }
  
  continueInit() {
    // 原来在init方法中renderer初始化后的逻辑
    this.initLight();
    this.initStats();
    this.initControls();
    this.initAxes();
    
    // 如果之前调用了run方法，现在启动循环
    if (this.shouldStart) {
      this.shouldStart = false;
      this.loop();
    }
  }
  initLight() {
    //   平行光1
    let directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.6);
    directionalLight1.position.set(400, 200, 200);
    //   平行光2
    let directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.6);
    directionalLight2.position.set(-400, -200, -300);
    // 环境光
    let ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    // 将光源添加到场景中
    this.addObject(directionalLight1);
    this.addObject(directionalLight2);
    this.addObject(ambientLight);
  }

  initStats() {
    if (!this.options.statsVisibel) return false;
    
    // 确保容器有有效的尺寸
    if (!this.container || this.container.offsetWidth === 0 || this.container.offsetHeight === 0) {
      console.warn('Container not ready for stats initialization, skipping...');
      return false;
    }
    
    this.stats = new Stats();
    
    // 确保stats的DOM元素有正确的尺寸
    if (this.stats.dom) {
      this.stats.dom.style.position = 'absolute';
      this.stats.dom.style.top = '0px';
      this.stats.dom.style.left = '0px';
      this.stats.dom.style.zIndex = '100';
    }
    
    this.container.appendChild(this.stats.dom);
  }
  initControls() {
    try {
      let {
        controls: { enableDamping, autoRotate, visibel, maxPolarAngle },
      } = this.options;
      if (!visibel) return false;
      // 轨道控制器，使相机围绕目标进行轨道运动（旋转|缩放|平移）
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.maxPolarAngle = maxPolarAngle;
      this.controls.autoRotate = autoRotate;
      this.controls.enableDamping = enableDamping;
    } catch (error) {
      console.log(error);
    }
  }
  initAxes() {
    if (!this.options.axesVisibel) return false;
    var axes = new THREE.AxesHelper(this.options.axesHelperSize);
    this.addObject(axes);
  }

  // 清空dom
  empty(elem) {
    while (elem && elem.lastChild) elem.removeChild(elem.lastChild);
  }
  /**
   * 添加对象到场景
   * @param {*} object  {} []
   */
  addObject(object) {
    if (isType('Array', object)) {
      this.scene.add(...object);
    } else {
      this.scene.add(object);
    }
  }
  /**
   * 移除对象
   * @param {*} object {} []
   */
  removeObject(object) {
    if (isType('Array', object)) {
      object.map((item) => {
        item.geometry.dispose();
      });
      this.scene.remove(...object);
    } else {
      object.geometry.dispose();
      this.scene.remove(object);
    }
  }
  /**
   * 重置
   */
  resize() {
    // 重新设置宽高
    let newWidth = this.container.offsetWidth || window.innerWidth;
    let newHeight = this.container.offsetHeight || window.innerHeight;
    
    // 确保尺寸有效
    this.options.width = Math.max(newWidth, 800);
    this.options.height = Math.max(newHeight, 600);
    
    if (this.renderer) {
      this.renderer.setSize(this.options.width, this.options.height);
    }
    // 重新设置相机的位置
    let rate = this.options.width / this.options.height;

    // 必須設置相機的比例，重置的時候才不会变形
    this.camera.aspect = rate;

    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
    // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
    this.camera.updateProjectionMatrix();
    
    // 如果stats还没有初始化（可能之前容器尺寸为0），现在重新尝试初始化
    if (this.options.statsVisibel && !this.stats) {
      this.initStats();
    }
  }
}
