import * as THREE from 'three'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'
import { MTLLoader } from 'three/addons/loaders/MTLLoader.js'
import gsap from 'gsap'

/**
 * 爆炸拆解管理器
 * 用于管理3D模型的拆解和还原动画
 */
export class ExplosionManager {
    constructor(scene) {
        this.scene = scene
        this.model = null
        this.isExploded = false
        this.animationDuration = 1
        this.explosionDistance = 1.5
        this.easeType = 'power2.inOut'

        // 初始化加载器
        this.gltfLoader = new GLTFLoader()
        this.objLoader = new OBJLoader()
        this.mtlLoader = new MTLLoader()

        // 设置DRACO解码器
        const dracoLoader = new DRACOLoader()
        dracoLoader.setDecoderPath('https://z2586300277.github.io/3d-file-server/js/three/draco/')
        this.gltfLoader.setDRACOLoader(dracoLoader)
    }

    /**
     * 加载GLTF/GLB模型
     * @param {string} url - 模型文件路径
     * @param {Function} onProgress - 加载进度回调
     * @param {Function} onError - 错误回调
     * @returns {Promise<THREE.Group>}
     */
    loadGLTF(url, onProgress, onError) {
        return new Promise((resolve, reject) => {
            this.gltfLoader.load(
                url,
                (gltf) => {
                    this.setupModel(gltf.scene)
                    resolve(gltf.scene)
                },
                onProgress,
                onError || reject
            )
        })
    }

    /**
     * 加载OBJ模型
     * @param {string} objUrl - OBJ文件路径
     * @param {string} mtlUrl - MTL文件路径（可选）
     * @param {Function} onProgress - 加载进度回调
     * @param {Function} onError - 错误回调
     * @returns {Promise<THREE.Group>}
     */
    loadOBJ(objUrl, mtlUrl = null, onProgress, onError) {
        return new Promise((resolve, reject) => {
            const loadObj = (obj) => {
                this.setupModel(obj)
                resolve(obj)
            }

            if (mtlUrl) {
                // 先加载材质
                this.mtlLoader.load(
                    mtlUrl,
                    (materials) => {
                        materials.preload()
                        this.objLoader.setMaterials(materials)
                        this.objLoader.load(
                            objUrl,
                            loadObj,
                            onProgress,
                            onError || reject
                        )
                    },
                    onProgress,
                    onError || reject
                )
            } else {
                // 直接加载OBJ
                this.objLoader.load(
                    objUrl,
                    loadObj,
                    onProgress,
                    onError || reject
                )
            }
        })
    }

    /**
     * 设置模型，准备拆解
     * @param {THREE.Object3D} model - 3D模型对象
     */
    setupModel(model) {
        // 移除旧模型
        if (this.model) {
            this.scene.remove(this.model)
        }

        this.model = model
        this.isExploded = false

        // 计算模型中心点
        const box = new THREE.Box3().setFromObject(model)
        const center = new THREE.Vector3()
        box.getCenter(center)
        model.center = center

        // 遍历所有mesh，保存初始位置
        model.traverse((child) => {
            if (child.isMesh) {
                // 转换为世界坐标
                child.localToWorld(child.position)
                // 保存初始位置
                child.startPosition = child.position.clone()
            }
        })

        // 添加到场景
        this.scene.add(model)
    }

    /**
     * 生成随机方向向量
     * @returns {Object} 包含x, y, z的随机方向
     */
    getRandomDirection() {
        const distance = () => Math.random() > 0.5 ? this.explosionDistance : -this.explosionDistance
        return {
            x: distance(),
            y: distance(),
            z: distance()
        }
    }

    /**
     * 拆解动画
     * @param {Object} options - 配置选项
     * @param {number} options.duration - 动画时长（秒）
     * @param {number} options.distance - 爆炸距离
     * @param {string} options.ease - 缓动函数类型
     * @param {Function} options.onComplete - 完成回调
     */
    explode(options = {}) {
        if (!this.model) {
            console.warn('ExplosionManager: 没有加载模型')
            return
        }

        if (this.isExploded) {
            console.warn('ExplosionManager: 模型已经拆解')
            return
        }

        const {
            duration = this.animationDuration,
            distance = this.explosionDistance,
            ease = this.easeType,
            onComplete
        } = options

        const originalDistance = this.explosionDistance
        this.explosionDistance = distance

        this.model.traverse((child) => {
            if (child.isMesh && child.startPosition) {
                const dir = this.getRandomDirection()
                gsap.to(child.position, {
                    x: child.startPosition.x + dir.x,
                    y: child.startPosition.y + dir.y,
                    z: child.startPosition.z + dir.z,
                    duration,
                    ease,
                    onComplete: () => {
                        if (onComplete && child === this.getLastMesh()) {
                            onComplete()
                        }
                    }
                })
            }
        })

        this.explosionDistance = originalDistance
        this.isExploded = true
    }

    /**
     * 还原动画
     * @param {Object} options - 配置选项
     * @param {number} options.duration - 动画时长（秒）
     * @param {string} options.ease - 缓动函数类型
     * @param {Function} options.onComplete - 完成回调
     */
    restore(options = {}) {
        if (!this.model) {
            console.warn('ExplosionManager: 没有加载模型')
            return
        }

        if (!this.isExploded) {
            console.warn('ExplosionManager: 模型未拆解')
            return
        }

        const {
            duration = this.animationDuration,
            ease = this.easeType,
            onComplete
        } = options

        this.model.traverse((child) => {
            if (child.isMesh && child.startPosition) {
                gsap.to(child.position, {
                    x: child.startPosition.x,
                    y: child.startPosition.y,
                    z: child.startPosition.z,
                    duration,
                    ease,
                    onComplete: () => {
                        if (onComplete && child === this.getLastMesh()) {
                            onComplete()
                        }
                    }
                })
            }
        })

        this.isExploded = false
    }

    /**
     * 获取最后一个mesh（用于回调判断）
     * @returns {THREE.Mesh|null}
     */
    getLastMesh() {
        let lastMesh = null
        if (this.model) {
            this.model.traverse((child) => {
                if (child.isMesh) {
                    lastMesh = child
                }
            })
        }
        return lastMesh
    }

    /**
     * 切换拆解/还原状态
     * @param {Object} options - 配置选项
     */
    toggle(options = {}) {
        if (this.isExploded) {
            this.restore(options)
        } else {
            this.explode(options)
        }
    }

    /**
     * 设置动画参数
     * @param {Object} params - 参数对象
     * @param {number} params.duration - 动画时长
     * @param {number} params.distance - 爆炸距离
     * @param {string} params.ease - 缓动函数类型
     */
    setAnimationParams(params) {
        if (params.duration !== undefined) {
            this.animationDuration = params.duration
        }
        if (params.distance !== undefined) {
            this.explosionDistance = params.distance
        }
        if (params.ease !== undefined) {
            this.easeType = params.ease
        }
    }

    /**
     * 获取当前模型
     * @returns {THREE.Object3D|null}
     */
    getModel() {
        return this.model
    }

    /**
     * 获取拆解状态
     * @returns {boolean}
     */
    getExplodedState() {
        return this.isExploded
    }

    /**
     * 移除模型
     */
    dispose() {
        if (this.model) {
            // 停止所有动画
            this.model.traverse((child) => {
                if (child.isMesh && child.position) {
                    gsap.killTweensOf(child.position)
                }
            })

            this.scene.remove(this.model)
            this.model = null
            this.isExploded = false
        }
    }
}

