/**
 * CollabOverlay — DOM-слой совместного редактирования (Team Create).
 *
 * Рисует поверх canvas студии:
 *   - панель «онлайн» (аватарки-кружки соавторов с цветом и ником);
 *   - 3D-курсоры соавторов (точка с ником, спроецированная из мировых
 *     координат в экранные);
 *   - подсветку чужого выделения (по selectedKey — обводим объект);
 *   - тосты («объект занят другим», «N присоединился»).
 *
 * Самодостаточный (как LoadingScreenOverlay): монтируется на parent canvas,
 * UI обновляется методами update(...). Кнопка «Пригласить» — снаружи (TopRibbon),
 * здесь только presence + курсоры.
 */
import { Vector3, Matrix } from '@babylonjs/core';

let _cssInjected = false;
function injectCss() {
    if (_cssInjected || typeof document === 'undefined') return;
    _cssInjected = true;
    const s = document.createElement('style');
    s.id = 'kbn-collab-css';
    s.textContent =
        '.kbnCollabCursor{position:absolute;transform:translate(-50%,-50%);pointer-events:none;z-index:62;transition:left 0.08s linear,top 0.08s linear;will-change:left,top}' +
        '.kbnCollabDot{width:14px;height:14px;border-radius:50%;border:2px solid #fff;box-shadow:0 1px 4px rgba(0,0,0,.5)}' +
        '.kbnCollabName{position:absolute;left:16px;top:-2px;white-space:nowrap;font:600 11px system-ui;color:#fff;padding:1px 6px;border-radius:6px;text-shadow:0 1px 2px rgba(0,0,0,.6)}' +
        '.kbnCollabBar{position:absolute;top:10px;left:50%;transform:translateX(-50%);z-index:63;display:flex;gap:6px;align-items:center;background:rgba(20,24,38,.78);padding:5px 10px;border-radius:20px;backdrop-filter:blur(6px);font:600 12px system-ui;color:#cdd6e6;pointer-events:auto}' +
        '.kbnCollabAva{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font:700 12px system-ui;color:#10131c;border:2px solid rgba(255,255,255,.25)}' +
        '.kbnCollabToast{position:absolute;bottom:80px;left:50%;transform:translateX(-50%);z-index:64;background:rgba(20,24,38,.92);color:#fff;padding:10px 18px;border-radius:10px;font:600 14px system-ui;box-shadow:0 8px 24px rgba(0,0,0,.5);opacity:0;transition:opacity .25s}';
    document.head.appendChild(s);
}

export class CollabOverlay {
    constructor(scene) {
        this.scene = scene;
        this.root = null;
        this.barEl = null;
        this.cursorsEl = null;
        this.toastEl = null;
        this._cursors = new Map();   // sessionId → {wrap, dot, name}
        this._presence = [];
        this._raf = null;
    }

    mount() {
        injectCss();
        const parent = (this.scene.canvas && this.scene.canvas.parentElement) || document.body;
        try { if (getComputedStyle(parent).position === 'static') parent.style.position = 'relative'; } catch (e) { /* ignore */ }

        const root = document.createElement('div');
        root.className = 'kbn-collab-root';
        root.style.cssText = 'position:absolute;inset:0;pointer-events:none;z-index:60;overflow:hidden';

        const bar = document.createElement('div');
        bar.className = 'kbnCollabBar';
        bar.innerHTML = '<span style="opacity:.8">👥 Соавторы:</span>';

        const cursors = document.createElement('div');
        cursors.style.cssText = 'position:absolute;inset:0';

        const toast = document.createElement('div');
        toast.className = 'kbnCollabToast';

        root.appendChild(bar);
        root.appendChild(cursors);
        root.appendChild(toast);
        parent.appendChild(root);

        this.root = root; this.barEl = bar; this.cursorsEl = cursors; this.toastEl = toast;
        this._startLoop();
    }

    /** Обновить список соавторов (из StudioCollab.onPresenceChange). */
    updatePresence(list) {
        this._presence = list || [];
        if (!this.barEl) return;
        // Перерисовать аватарки.
        const others = this._presence;
        let html = '<span style="opacity:.8">👥</span>';
        for (const c of others) {
            const initial = (c.username || '?').trim().charAt(0).toUpperCase() || '?';
            const ring = c.me ? 'box-shadow:0 0 0 2px #fff' : '';
            html += `<div class="kbnCollabAva" title="${escapeHtml(c.username)}${c.isHost ? ' (хост)' : ''}${c.me ? ' — вы' : ''}" style="background:${c.color};${ring}">${escapeHtml(initial)}</div>`;
        }
        html += `<span style="opacity:.7;margin-left:4px">${others.length}</span>`;
        this.barEl.innerHTML = html;
        // Курсоры пересоберём в loop.
        this._syncCursorEls();
    }

    _syncCursorEls() {
        const present = new Set(this._presence.filter(c => !c.me).map(c => c.sessionId));
        // удалить ушедших
        for (const [sid, el] of this._cursors) {
            if (!present.has(sid)) { try { el.wrap.remove(); } catch (e) { /* ignore */ } this._cursors.delete(sid); }
        }
        // добавить новых
        for (const c of this._presence) {
            if (c.me) continue;
            if (!this._cursors.has(c.sessionId)) {
                const wrap = document.createElement('div');
                wrap.className = 'kbnCollabCursor';
                const dot = document.createElement('div');
                dot.className = 'kbnCollabDot';
                const name = document.createElement('div');
                name.className = 'kbnCollabName';
                wrap.appendChild(dot); wrap.appendChild(name);
                this.cursorsEl.appendChild(wrap);
                this._cursors.set(c.sessionId, { wrap, dot, name });
            }
            const el = this._cursors.get(c.sessionId);
            el.dot.style.background = c.color;
            el.name.style.background = c.color;
            el.name.textContent = c.username;
        }
    }

    /** Каждый кадр проецируем 3D-курсоры соавторов в экранные координаты. */
    _startLoop() {
        const tick = () => {
            this._raf = requestAnimationFrame(tick);
            if (!this.cursorsEl || !this._presence.length) return;
            const scene = this.scene.scene;
            const cam = this.scene.camera;
            const eng = this.scene.engine;
            if (!scene || !cam || !eng) return;
            for (const c of this._presence) {
                if (c.me) continue;
                const el = this._cursors.get(c.sessionId);
                if (!el) continue;
                const cur = c.cursor;
                if (!cur || (cur.x === 0 && cur.y === 0 && cur.z === 0)) { el.wrap.style.display = 'none'; continue; }
                const sp = this._project(cur.x, cur.y, cur.z, scene, cam, eng);
                if (!sp) { el.wrap.style.display = 'none'; continue; }
                el.wrap.style.display = 'block';
                el.wrap.style.left = sp.x + 'px';
                el.wrap.style.top = sp.y + 'px';
            }
        };
        this._raf = requestAnimationFrame(tick);
    }

    /** Спроецировать мировую точку в экранные координаты canvas. */
    _project(x, y, z, scene, cam, eng) {
        try {
            const w = eng.getRenderWidth();
            const h = eng.getRenderHeight();
            const p = Vector3.Project(
                new Vector3(x, y, z),
                Matrix.Identity(),
                scene.getTransformMatrix(),
                cam.viewport.toGlobal(w, h)
            );
            if (p.z < 0 || p.z > 1) return null; // за камерой
            // переводим из render-пикселей в css-пиксели canvas
            const canvas = eng.getRenderingCanvas();
            const rect = canvas.getBoundingClientRect();
            const sx = rect.width / w, sy = rect.height / h;
            return { x: p.x * sx, y: p.y * sy };
        } catch (e) { return null; }
    }

    toast(text) {
        if (!this.toastEl) return;
        this.toastEl.textContent = text;
        this.toastEl.style.opacity = '1';
        clearTimeout(this._toastT);
        this._toastT = setTimeout(() => { if (this.toastEl) this.toastEl.style.opacity = '0'; }, 2600);
    }

    dispose() {
        if (this._raf) cancelAnimationFrame(this._raf);
        try { this.root?.remove(); } catch (e) { /* ignore */ }
        this.root = null; this._cursors.clear();
    }
}

function escapeHtml(s) {
    return String(s == null ? '' : s).replace(/[&<>"']/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[m]));
}
