<template>
  <div class="three-preview" :style="getAreaStyle()">
    <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />

    <div ref="three" class="three">
      <SvgIcon
        :class-name="iconName()"
        :icon-class="icon()"
        :size="isFullScreen ? '32px' : '16px'"
        @click="handleToggleFullScreen"
      />
    </div>
  </div>
</template>

<script>
import PreviewMixin from '../common/PreviewMixin';

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

import { get3DModelData } from '@/views/book/courseware/data/3dModel';
import { toggleFullScreen } from '@/utils/common';
import { GetFileStoreInfo } from '@/api/app';

export default {
  name: 'ThreeModelPreview',
  mixins: [PreviewMixin],
  data() {
    return {
      data: get3DModelData(),
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      animationId: null,
      isFullScreen: false, // 是否全屏
      loaded: false, // 是否加载完成
    };
  },
  watch: {
    'data.model_list': {
      handler(val) {
        if (val && val.length > 0) {
          this.loadModel();
        }
      },
      immediate: true,
      deep: true,
    },
  },
  mounted() {
    this.initThree();
    window.addEventListener('fullscreenchange', this.onWindowResize);
  },
  beforeDestroy() {
    this.cleanup();
    window.removeEventListener('fullscreenchange', this.onWindowResize);
  },
  methods: {
    iconName() {
      if (this.data.model_list.length === 0) return 'fullscreen-btn';
      return this.loaded ? (this.isFullScreen ? 'exit-fullscreen' : 'fullscreen-btn') : 'loading';
    },
    icon() {
      if (this.data.model_list.length === 0) return '';
      return this.loaded ? (this.isFullScreen ? 'exit-fullscreen' : 'fullscreen') : 'loading';
    },
    initThree() {
      const container = this.$refs.three;
      if (!container) return;

      // 创建场景
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(0xf0f0f0);

      // 创建相机
      const width = container.clientWidth;
      const height = container.clientHeight;
      this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
      this.camera.position.set(5, 5, 5);

      // 创建渲染器
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setSize(width, height);
      this.renderer.shadowMap.enabled = true;
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
      container.appendChild(this.renderer.domElement);

      // 添加光源
      const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
      this.scene.add(ambientLight);

      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
      directionalLight.position.set(10, 10, 5);
      directionalLight.castShadow = true;
      this.scene.add(directionalLight);

      // 添加控制器
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.enableDamping = true;
      this.controls.dampingFactor = 0.25;

      // 开始渲染循环
      this.animate();

      // 监听窗口大小变化
      window.addEventListener('resize', this.onWindowResize);
    },

    async loadModel() {
      if (!this.data.model_list || this.data.model_list.length === 0) {
        return;
      }

      const fileStore = await GetFileStoreInfo({ file_id: this.data.model_list[0].file_id });
      if (!fileStore || fileStore.error) {
        console.error('模型文件加载失败:', fileStore);
        return;
      }
      const modelUrl = fileStore.file_url;
      // 根据文件扩展名选择合适的加载器
      const extension = modelUrl.split('.').pop().toLowerCase();
      let loader = null;

      switch (extension) {
        case 'gltf':
        case 'glb':
          loader = new GLTFLoader();
          this.loadGLTF(loader, modelUrl);
          break;
        case 'fbx':
          loader = new FBXLoader();
          this.loadFBX(loader, modelUrl);
          break;
        case 'obj':
          loader = new OBJLoader();
          this.loadOBJ(loader, modelUrl);
          break;
        default:
          console.error('不支持的模型格式:', extension);
      }
    },

    loadGLTF(loader, url) {
      loader.load(
        url,
        (gltf) => {
          const model = gltf.scene;
          this.addModelToScene(model);

          // 如果模型有动画，播放第一个动画
          if (gltf.animations && gltf.animations.length > 0) {
            this.mixer = new THREE.AnimationMixer(model);
            const action = this.mixer.clipAction(gltf.animations[0]);
            action.play();
          }
        },
        (progress) => {
          console.log('加载进度:', `${(progress.loaded / progress.total) * 100}%`);
          if (progress.loaded >= progress.total) {
            this.loaded = true;
          }
        },
        (error) => {
          console.error('GLTF模型加载失败:', error);
        },
      );
    },

    loadFBX(loader, url) {
      loader.load(
        url,
        (fbx) => {
          this.addModelToScene(fbx);
        },
        (progress) => {
          console.log('加载进度:', `${(progress.loaded / progress.total) * 100}%`);
          if (progress.loaded >= progress.total) {
            this.loaded = true;
          }
        },
        (error) => {
          console.error('FBX模型加载失败:', error);
        },
      );
    },

    loadOBJ(loader, url) {
      loader.load(
        url,
        (obj) => {
          this.addModelToScene(obj);
        },
        (progress) => {
          console.log('加载进度:', `${(progress.loaded / progress.total) * 100}%`);
          if (progress.loaded >= progress.total) {
            this.loaded = true;
          }
        },
        (error) => {
          console.error('OBJ模型加载失败:', error);
        },
      );
    },

    addModelToScene(model) {
      // 计算模型的包围盒，用于自动调整相机位置
      const box = new THREE.Box3().setFromObject(model);
      const center = box.getCenter(new THREE.Vector3());
      const size = box.getSize(new THREE.Vector3());

      // 将模型移到原点
      model.position.sub(center);
      this.scene.add(model);

      // 自动调整相机位置
      const maxDim = Math.max(size.x, size.y, size.z);
      const fov = this.camera.fov * (Math.PI / 180);
      let cameraZ = Math.abs(maxDim / 2 / Math.tan(fov / 2));
      cameraZ *= 1.5; // 稍微远一点以便观察

      this.camera.position.set(cameraZ, cameraZ, cameraZ);
      this.camera.lookAt(0, 0, 0);
      this.controls.target.set(0, 0, 0);
    },

    animate() {
      this.animationId = requestAnimationFrame(this.animate);

      // 更新控制器
      if (this.controls) {
        this.controls.update();
      }

      // 更新动画混合器
      if (this.mixer) {
        this.mixer.update(0.016); // 假设60fps
      }

      // 渲染场景
      if (this.renderer && this.scene && this.camera) {
        this.renderer.render(this.scene, this.camera);
      }
    },

    onWindowResize() {
      const container = this.$refs.three;
      this.isFullScreen = document.fullscreenElement !== null;
      if (!container || !this.camera || !this.renderer) return;

      let height = 0;
      let width = 0;

      // 检查是否在全屏状态
      if (document.fullscreenElement) {
        // 全屏状态下使用整个屏幕尺寸
        width = window.innerWidth;
        height = window.innerHeight;
      } else {
        // 非全屏状态下使用容器尺寸
        width = container.clientWidth;
        height = container.clientHeight;
      }

      // 更新相机宽高比
      this.camera.aspect = width / height;
      this.camera.updateProjectionMatrix();

      // 更新渲染器尺寸
      this.renderer.setSize(width, height);
    },

    cleanup() {
      // 停止动画循环
      if (this.animationId) {
        cancelAnimationFrame(this.animationId);
      }

      // 移除事件监听器
      window.removeEventListener('resize', this.onWindowResize);

      // 清理Three.js资源
      if (this.renderer) {
        this.renderer.dispose();
        const container = this.$refs.three;
        if (container && container.contains(this.renderer.domElement)) {
          container.removeChild(this.renderer.domElement);
        }
      }

      if (this.scene) {
        this.scene.clear();
      }
    },

    handleToggleFullScreen() {
      if (!this.$refs.three) return;
      if (!this.loaded) {
        this.$message.warning('请等待模型加载完成后，再切换全屏');
        return;
      }
      toggleFullScreen(this.$refs.three);
      // 延迟一帧来确保DOM已经更新
      this.$nextTick(() => {
        setTimeout(() => {
          this.onWindowResize();
        }, 100);
      });
    },
  },
};
</script>

<style lang="scss" scoped>
@use '@/styles/mixin.scss' as *;

.three-preview {
  @include preview-base;

  .three {
    position: relative;
    min-height: 104px;
    overflow: hidden;

    .loading {
      position: absolute;
      top: 10px;
      right: 10px;
      color: #999;

      @include spin;
    }

    .fullscreen-btn {
      position: absolute;
      top: 10px;
      right: 10px;
      z-index: 999;
      cursor: pointer;
    }

    .exit-fullscreen {
      position: fixed;
      top: 24px;
      right: 24px;
      z-index: 999;
      cursor: pointer;
    }
  }
}
</style>
