/**
 * rbxl-lua-integration.js — вспомогательные функции для импорта .rbxl-карт.
 *
 * Старый отдельный Worker-based runtime удалён (2026-06-08): импортированные
 * Lua-скрипты теперь идут через тот же LuaSharedSandbox что и user-Lua
 * (см. GameRuntime.start()). Этот файл оставлен только для:
 *   - unpackRobloxLuaCode() — распаковка Lua из JS-комментария-обёртки;
 *   - handleLuaCommand() — обработка partSet/sceneCreate/sceneDelete/playerCmd
 *     команд от Lua-VM в BabylonScene.
 */

/** Распаковка lua_source из packed-кода. */
export function unpackRobloxLuaCode(code) {
    const openTag = '/[*] lua_source:\n'.replace('[*]', '*');
    const i = code.indexOf(openTag);
    if (i < 0) return null;
    const start = i + openTag.length;
    const closeIdx = code.lastIndexOf('\n*' + '/');
    if (closeIdx < start) return null;
    return code.slice(start, closeIdx);
}

/** Парсит JSON-метадату из 2-й строки packed-кода (`// {"roblox_class":..., "enabled": true}`). */
export function parseRobloxLuaMeta(code) {
    if (typeof code !== 'string') return null;
    const lines = code.split('\n');
    if (lines.length < 2) return null;
    const metaLine = lines[1];
    if (!metaLine.startsWith('// ')) return null;
    try {
        return JSON.parse(metaLine.slice(3));
    } catch (_) {
        return null;
    }
}

/** Сцена → snap для shim'а (workspace:GetChildren). */
export function buildLuaSceneSnap(primitives) {
    const out = { primitives: {} };
    if (!Array.isArray(primitives)) return out;
    for (const p of primitives) {
        out.primitives[p.id] = {
            id: p.id, type: p.type, name: p.name,
            x: p.x, y: p.y, z: p.z,
            sx: p.sx, sy: p.sy, sz: p.sz,
            color: p.color, material: p.material,
            anchored: !!p.anchored, canCollide: p.canCollide !== false,
            opacity: typeof p.opacity === 'number' ? p.opacity : 1,
        };
    }
    return out;
}

/**
 * GUI-tree для shim'а. Mapping origin → __roblox_class.
 * scene.gui — массив элементов с {id, type, name, parentId, ...origin}.
 * Возвращаем массив сохраняя порядок parent → child (важно для tree-сборки).
 */
export function buildLuaGuiTree(guiElements) {
    if (!Array.isArray(guiElements)) return [];
    const out = [];
    for (const el of guiElements) {
        // origin = 'roblox-textbutton' → 'TextButton'
        let rblClass = 'Frame';
        const origin = el.origin || '';
        if (origin.startsWith('roblox-')) {
            const tail = origin.slice(7);
            rblClass = tail.charAt(0).toUpperCase() + tail.slice(1);
            // Camel-case "textbutton" → "TextButton"
            if (rblClass.toLowerCase() === 'textbutton') rblClass = 'TextButton';
            else if (rblClass.toLowerCase() === 'textlabel') rblClass = 'TextLabel';
            else if (rblClass.toLowerCase() === 'imagebutton') rblClass = 'ImageButton';
            else if (rblClass.toLowerCase() === 'imagelabel') rblClass = 'ImageLabel';
            else if (rblClass.toLowerCase() === 'textbox') rblClass = 'TextBox';
            else if (rblClass.toLowerCase() === 'scrollingframe') rblClass = 'ScrollingFrame';
            else if (rblClass.toLowerCase() === 'frame') rblClass = 'Frame';
        } else {
            // Если origin не задан — гадаем по type
            const t = el.type;
            if (t === 'button') rblClass = 'TextButton';
            else if (t === 'text') rblClass = 'TextLabel';
            else if (t === 'image') rblClass = 'ImageLabel';
            else if (t === 'textbox') rblClass = 'TextBox';
        }
        out.push({
            id: el.id,
            name: el.name || rblClass,
            parentId: el.parentId || null,
            visible: el.visible !== false,
            text: el.text || '',
            __roblox_class: rblClass,
        });
    }
    return out;
}

/**
 * Обработка IPC команд от worker'а — мапим на действия в Babylon-сцене.
 */
export function handleLuaCommand(_scriptId, cmd, payload, runtime) {
    if (cmd === 'log') {
        const fn = payload?.level === 'error' ? console.error
            : payload?.level === 'warn' ? console.warn : console.log;
        fn('[rbxl-lua]', payload?.text || '');
        return;
    }
    if (cmd === 'partSet') {
        const pm = runtime.scene3d?.primitiveManager;
        if (!pm) {
            console.warn('[partSet] no primitiveManager. scene3d=', !!runtime.scene3d);
            return;
        }
        const primId = payload?.primId;
        const prop = payload?.prop;
        const value = payload?.value;
        const patch = {};
        if (prop === 'position' && value) {
            patch.x = value.x; patch.y = value.y; patch.z = value.z;
        } else if (prop === 'cframe' && value) {
            patch.x = value.x; patch.y = value.y; patch.z = value.z;
            patch.rotationX = value.rx; patch.rotationY = value.ry; patch.rotationZ = value.rz;
        } else if (prop === 'size' && value) {
            patch.sx = value.sx; patch.sy = value.sy; patch.sz = value.sz;
        } else if (prop === 'color') patch.color = value;
        else if (prop === 'material') patch.material = value;
        else if (prop === 'anchored') patch.anchored = value;
        else if (prop === 'canCollide') patch.canCollide = value;
        else if (prop === 'opacity') patch.opacity = value;
        try {
            if (typeof pm.updateInstance === 'function') pm.updateInstance(primId, patch);
            else if (typeof pm.applyPatch === 'function') pm.applyPatch(primId, patch);
            else if (typeof pm.update === 'function') pm.update(primId, patch);
        } catch (e) {
            console.error('[partSet] updateInstance failed:', e);
        }
        return;
    }
    if (cmd === 'sceneCreate') {
        // Lua: Instance.new("Part") + part.Parent = workspace → создание примитива.
        // payload: { primId (предложенный id), type, x, y, z, sx, sy, sz, color, anchored }
        try {
            const pm = runtime.scene3d?.primitiveManager;
            if (!pm || typeof pm.addInstance !== 'function') return;
            const opts = {
                id: payload?.primId,
                x: payload?.x || 0, y: payload?.y || 0, z: payload?.z || 0,
                sx: payload?.sx || 1, sy: payload?.sy || 1, sz: payload?.sz || 1,
                color: payload?.color,
                anchored: payload?.anchored !== false,
                canCollide: payload?.canCollide !== false,
            };
            pm.addInstance(payload?.type || 'cube', opts);
            // Если unanchored — регистрируем в физике на лету, иначе он не падает.
            if (opts.anchored === false) {
                try {
                    const dm = runtime.scene3d?.dynamics;
                    const data = pm.instances?.get?.(opts.id);
                    if (dm && data && typeof dm.registerPrimitive === 'function') {
                        dm.registerPrimitive(data);
                    }
                } catch (e) {
                    console.warn('[sceneCreate] registerPrimitive failed', e);
                }
            }
        } catch (e) {
            console.error('[sceneCreate]', e);
        }
        return;
    }
    if (cmd === 'sceneDelete') {
        // Lua: part:Destroy() → удаление примитива.
        try {
            const pm = runtime.scene3d?.primitiveManager;
            if (!pm || typeof pm.removeInstance !== 'function') return;
            const id = payload?.primId;
            if (id != null) pm.removeInstance(Number(id));
        } catch (e) {
            console.error('[sceneDelete]', e);
        }
        return;
    }
    if (cmd === 'partVel') {
        try {
            const pm = runtime.scene3d?.primitiveManager;
            if (pm && typeof pm.setVelocity === 'function') {
                pm.setVelocity(payload.primId, payload.vx, payload.vy, payload.vz);
            }
        } catch (e) {}
        return;
    }
    if (cmd === 'playerCmd') {
        try {
            const p = runtime.game?.player;
            if (!p) return;
            const method = payload?.method;
            const args = payload?.args || [];
            if (method === 'teleport') p.teleport && p.teleport(args[0], args[1], args[2]);
            else if (method === 'setWalkSpeed') p.setWalkSpeed && p.setWalkSpeed(args[0]);
            else if (method === 'setJumpPower') p.setJumpPower && p.setJumpPower(args[0]);
            else if (method === 'setHealth') p.setHealth && p.setHealth(args[0]);
            else if (method === 'die') p.die && p.die();
            else if (method === 'damage' || method === 'takeDamage') p.damage && p.damage(args[0]);
        } catch (e) {}
        return;
    }
    if (cmd === 'guiUpdate') {
        // TODO: scripts setting Visible/Text/Color on GUI → передать в GuiManager
        return;
    }
}
