/**
 * LabelManager — billboard-метки (текст-плашки) над 3D-объектами.
 *
 * Используется для game.scene.setLabel(ref, text) — имена/HP над
 * персонажами, врагами, предметами. Метка всегда повёрнута лицом к камере
 * (billboardMode=7), всегда поверх геометрии (renderingGroupId=1).
 *
 * Метка привязывается к мешу объекта (parent) и висит над ним.
 */
import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder';
import { Color3 } from '@babylonjs/core/Maths/math.color';

export class LabelManager {
    constructor(scene) {
        this.scene = scene;
        // ref-строка объекта → { plane, tex, mat }
        this.labels = new Map();
    }

    /**
     * Установить/обновить метку над объектом.
     *   ref      — ref-строка объекта (от scene.spawn / scene.find).
     *   anchorMesh — Babylon-меш объекта (метка крепится к нему).
     *   text     — текст метки.
     *   opts     — { color: '#fff', height: 2.5 (м над объектом), size: 1 }
     */
    setLabel(ref, anchorMesh, text, opts = {}) {
        if (!anchorMesh) return;
        const color = opts.color || '#ffffff';
        const heightAbove = Number.isFinite(opts.height) ? opts.height : 2.5;
        const sizeMul = Number.isFinite(opts.size) ? opts.size : 1;

        // Если метка уже есть — пересоздаём (текст/цвет могли измениться).
        this.clearLabel(ref);

        const W = 1024, H = 256;
        const tex = new DynamicTexture(`lblTex_${ref}_${Date.now()}`,
            { width: W, height: H }, this.scene, true);
        tex.updateSamplingMode?.(3);   // TRILINEAR
        tex.anisotropicFilteringLevel = 8;
        const ctx = tex.getContext();
        ctx.clearRect(0, 0, W, H);
        ctx.font = 'bold 120px "Roboto Condensed", "Segoe UI", sans-serif';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.lineWidth = 16;
        ctx.lineJoin = 'round';
        ctx.strokeStyle = '#000';
        ctx.strokeText(String(text), W / 2, H / 2);
        ctx.fillStyle = color;
        ctx.fillText(String(text), W / 2, H / 2);
        tex.update(true);
        tex.hasAlpha = true;

        const plane = MeshBuilder.CreatePlane(`lbl_${ref}`,
            { width: 2.2 * sizeMul, height: 0.55 * sizeMul }, this.scene);
        const mat = new StandardMaterial(`lblMat_${ref}`, this.scene);
        mat.diffuseTexture = tex;
        mat.diffuseTexture.hasAlpha = true;
        mat.emissiveColor = new Color3(1, 1, 1);
        mat.disableLighting = true;
        mat.backFaceCulling = false;
        mat.disableDepthWrite = true;
        plane.material = mat;
        plane.billboardMode = 7;        // всегда лицом к камере
        plane.renderingGroupId = 1;     // поверх геометрии
        plane.isPickable = false;
        // Крепим к объекту: метка висит над ним и двигается вместе с ним.
        plane.parent = anchorMesh;
        plane.position.set(0, heightAbove, 0);

        this.labels.set(ref, { plane, tex, mat });
    }

    /** Убрать метку с объекта. */
    clearLabel(ref) {
        const rec = this.labels.get(ref);
        if (!rec) return;
        try { rec.plane.dispose(); } catch (e) { /* ignore */ }
        try { rec.tex.dispose(); } catch (e) { /* ignore */ }
        try { rec.mat.dispose(); } catch (e) { /* ignore */ }
        this.labels.delete(ref);
    }

    /** Удалить все метки (при выходе из Play). */
    clearAll() {
        for (const ref of [...this.labels.keys()]) this.clearLabel(ref);
    }
}
