/**
 * GdDiamond — визуал алмазов и эффект подбора для GD-уровней.
 *
 * 1. Находит все primitive id ∈ [14001, 14002] и заменяет sphere
 *    на красивый **октаэдр-кристалл** с emissive свечением и точечным светом.
 * 2. Idle-анимация: вращение + плавание вверх-вниз.
 * 3. При исчезновении (setEnabled(false) или setVisible(false)) — взрыв ParticleSystem
 *    на 1 секунду на месте алмаза.
 *
 * Подключается в BabylonScene.enterPlayMode.
 */
import {
    Vector3, Color3, Color4, StandardMaterial, MeshBuilder, PointLight,
    ParticleSystem, Texture,
} from '@babylonjs/core';

const DIAMOND_IDS = [14001, 14002];

export class GdDiamond {
    constructor() {
        this.scene = null;
        this._scene3d = null;
        this._items = [];   // [{ primId, root, mesh, light, baseY, phase }]
        this._onBeforeRender = null;
        this._t = 0;
    }

    attach(scene, scene3d) {
        if (!scene || !scene3d) return;
        this.scene = scene;
        this._scene3d = scene3d;
        // Отложенно — primitives могут не быть загружены
        let attempts = 0;
        const tryAttach = () => {
            attempts++;
            const pm = scene3d.primitiveManager;
            if (!pm || !pm.instances) {
                if (attempts < 10) setTimeout(tryAttach, 200);
                return;
            }
            this._replaceDiamonds();
            this._setupAnim();
        };
        tryAttach();
    }

    _replaceDiamonds() {
        const pm = this._scene3d.primitiveManager;
        let n = 0;
        for (const id of DIAMOND_IDS) {
            const data = pm.instances.get(id);
            if (!data || !data.mesh) continue;
            const orig = data.mesh;
            const x = data.x, y = data.y, z = data.z || 0;

            // Сделать красивый октаэдр-кристалл вместо sphere
            const crystal = MeshBuilder.CreatePolyhedron(`gd_diamond_${id}`,
                { type: 1, size: 0.55 }, this.scene);   // type=1 = octahedron
            crystal.position.set(x, y, z);

            // Материал — голубой стеклянный с свечением
            const mat = new StandardMaterial(`gd_diamond_mat_${id}`, this.scene);
            mat.diffuseColor = new Color3(0.5, 0.85, 1.0);
            mat.emissiveColor = new Color3(0.3, 0.7, 1.0);
            mat.specularColor = new Color3(1, 1, 1);
            mat.specularPower = 128;
            mat.alpha = 0.85;
            crystal.material = mat;

            // Точечный свет для атмосферы
            const light = new PointLight(`gd_diamond_light_${id}`, new Vector3(x, y, z), this.scene);
            light.diffuse = new Color3(0.4, 0.8, 1.0);
            light.specular = new Color3(0.5, 0.9, 1.0);
            light.intensity = 0.5;
            light.range = 4;

            // Прячем исходный sphere (визуально — кристалл его заменяет)
            try { orig.setEnabled(false); } catch (e) {}

            this._items.push({
                primId: id,
                origMesh: orig,
                mesh: crystal,
                light,
                baseY: y,
                phase: id * 0.7,
                collected: false,
            });
            // Если data.visible уже false (скрипт уровня загрузил флаг из save —
            // алмаз был забран в прошлый заход), кристалл скрыть без эффекта.
            if (data.visible === false) {
                try { crystal.setEnabled(false); } catch (e) {}
                try { light && light.setEnabled(false); } catch (e) {}
                this._items[this._items.length - 1].collected = true;
            }
            n++;
        }
        console.log(`[GdDiamond] установлено ${n} кристаллов`);
    }

    _setupAnim() {
        const pm = this._scene3d.primitiveManager;
        this._onBeforeRender = () => {
            this._t += 0.016;
            for (const it of this._items) {
                if (it.collected || !it.mesh) continue;
                // Вращение по Y
                it.mesh.rotation.y = this._t * 1.5 + it.phase;
                // Плавание вверх-вниз
                const bob = Math.sin(this._t * 2 + it.phase) * 0.25;
                it.mesh.position.y = it.baseY + bob;
                if (it.light) it.light.position.y = it.baseY + bob;
                // Подбор определяем по data.visible — скрипт уровня вызывает
                // game.scene.setVisible('primitive:14001', false) когда забрал.
                // Это надёжно: setEnabled false мы сами установили в _replaceDiamonds.
                const data = pm && pm.instances.get(it.primId);
                if (data && data.visible === false) {
                    this._triggerCollect(it);
                }
            }
        };
        this.scene.onBeforeRenderObservable.add(this._onBeforeRender);
    }

    _triggerCollect(it) {
        if (it.collected) return;
        it.collected = true;
        const pos = it.mesh.position.clone();
        // Эффект частиц
        try {
            const ps = new ParticleSystem(`diamond_burst_${it.primId}`, 60, this.scene);
            // Используем процедурную текстуру (точка) если нет ассета
            ps.particleTexture = null;   // Babylon делает квадратик по умолчанию
            ps.emitter = pos;
            ps.minEmitBox = new Vector3(-0.1, -0.1, -0.1);
            ps.maxEmitBox = new Vector3(0.1, 0.1, 0.1);
            ps.color1 = new Color4(0.5, 0.9, 1.0, 1);
            ps.color2 = new Color4(0.9, 1.0, 1.0, 1);
            ps.colorDead = new Color4(0.3, 0.5, 0.9, 0);
            ps.minSize = 0.08; ps.maxSize = 0.20;
            ps.minLifeTime = 0.4; ps.maxLifeTime = 1.0;
            ps.emitRate = 0;   // burst-режим
            ps.manualEmitCount = 60;
            ps.gravity = new Vector3(0, -3, 0);
            ps.direction1 = new Vector3(-3, 4, -3);
            ps.direction2 = new Vector3(3, 8, 3);
            ps.minEmitPower = 1; ps.maxEmitPower = 4;
            ps.updateSpeed = 0.02;
            ps.disposeOnStop = true;
            ps.start();
            // Стоп через 200мс (один burst)
            setTimeout(() => { try { ps.stop(); } catch (e) {} }, 200);
        } catch (e) { console.warn('[GdDiamond] particles failed', e); }
        // Кристалл — scale-up и fade за 400мс
        const mesh = it.mesh;
        const light = it.light;
        const startT = performance.now();
        const DUR = 400;
        const fadeStep = () => {
            const elapsed = performance.now() - startT;
            if (elapsed > DUR) {
                try { mesh.dispose(); } catch (e) {}
                try { light && light.dispose(); } catch (e) {}
                return;
            }
            const t = elapsed / DUR;
            const s = 1 + t * 1.5;
            mesh.scaling.set(s, s, s);
            if (mesh.material) mesh.material.alpha = 0.85 * (1 - t);
            if (light) light.intensity = 0.5 * (1 - t);
            requestAnimationFrame(fadeStep);
        };
        requestAnimationFrame(fadeStep);
    }

    dispose() {
        if (!this.scene) return;
        try {
            if (this._onBeforeRender) {
                this.scene.onBeforeRenderObservable.removeCallback(this._onBeforeRender);
                this._onBeforeRender = null;
            }
        } catch (e) {}
        for (const it of this._items) {
            try { it.mesh && it.mesh.dispose(); } catch (e) {}
            try { it.light && it.light.dispose(); } catch (e) {}
        }
        this._items = [];
        this.scene = null;
        this._scene3d = null;
    }
}
