/**
 * rbxl-lua-tween.test.js — тесты TweenService.
 */
import { LuaFactory } from 'wasmoon';
import { registerRobloxApi } from '../src/engine/roblox-shim.js';
import { RobloxScheduler } from '../src/engine/roblox-scheduler.js';
import { RobloxTweenManager } from '../src/engine/roblox-tween.js';

const SCENE = {
    primitives: {
        1: { id: 1, type: 'cube', name: 'Movable', x: 0, y: 5, z: 0, sx: 1, sy: 1, sz: 1,
             color: '#ffffff', material: 'glossy', anchored: false, canCollide: true, opacity: 1 },
    },
};

async function run(luaSource, ticks = []) {
    const factory = new LuaFactory();
    const lua = await factory.createEngine();
    const sent = [];
    const send = (cmd, payload) => sent.push({ cmd, payload });
    registerRobloxApi(lua, { getSceneSnap: () => SCENE, targetPrimitiveId: 1, send });
    const sched = new RobloxScheduler(lua);
    sched.install();
    const tweenMgr = new RobloxTweenManager();
    tweenMgr.install(lua);

    await sched.spawnMain(luaSource);
    for (const dt of ticks) {
        await sched.tick(dt);
        tweenMgr.tick(dt);
    }
    lua.global.close();
    return { logs: sent.filter(s => s.cmd === 'log').map(s => s.payload),
             partSets: sent.filter(s => s.cmd === 'partSet').map(s => s.payload) };
}

const TESTS = [
    {
        name: 'TweenInfo создаётся',
        lua: `
            local info = TweenInfo.new(2, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
            print("time:", info.Time, "style:", info.EasingStyle)
        `,
        ticks: [],
        expectLogs: [{ level: 'info', text: 'time:\t2\tstyle:\tLinear' }],
    },
    {
        name: 'TweenService:Create + Play (Linear)',
        lua: `
            local TS = game:GetService("TweenService")
            local p = workspace:FindFirstChild("Movable")
            local info = TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
            local tw = TS:Create(p, info, { Position = Vector3.new(10, 5, 0) })
            tw:Play()
            print("started")
        `,
        ticks: [0.5, 0.5, 0.1],  // больше 1 сек — должен завершиться
        // Ожидаем что хотя бы один partSet с prop=position
        expectPartSet: { primId: 1, prop: 'position' },
    },
];

(async () => {
    let passed = 0, failed = 0;
    for (const t of TESTS) {
        try {
            const r = await run(t.lua, t.ticks);
            let ok = true;
            let reason = '';
            for (const exp of (t.expectLogs || [])) {
                const found = r.logs.find(l => l.level === exp.level && l.text === exp.text);
                if (!found) { ok = false; reason = `missing log: ${exp.text}`; break; }
            }
            if (t.expectPartSet) {
                const found = r.partSets.find(p => p.primId === t.expectPartSet.primId && p.prop === t.expectPartSet.prop);
                if (!found) {
                    ok = false; reason = `missing partSet: ${JSON.stringify(t.expectPartSet)}; got: ${JSON.stringify(r.partSets.slice(0,3))}`;
                }
            }
            if (ok) { console.log(`✓ ${t.name}`); passed++; }
            else { console.log(`✗ ${t.name} — ${reason}`); failed++; }
        } catch (e) {
            console.log(`✗ ${t.name} — exception: ${e}`);
            failed++;
        }
    }
    console.log(`\n${passed} passed, ${failed} failed`);
    process.exit(failed > 0 ? 1 : 0);
})();
