import { describe, expect, it } from 'vitest';
import { GameState } from '../../core/GameState';
import { Camera } from '../../render/Camera';
import { CutsceneRunner } from '../CutsceneRunner';

/** Продвинуть раннер: dt N раз. */
function tick(runner: CutsceneRunner, dt: number, times: number): void {
    for (let i = 0; i < times; i++) runner.update(dt);
}

/** Фиктивный «взгляд»: камера с заданным центром. */
function cameraAt(x: number, y: number): Camera {
    const cam = new Camera(480, 270);
    cam.x = x;
    cam.y = y;
    return cam;
}

describe('CutsceneRunner — последовательность шагов', () => {
    it('шаги выполняются по порядку, wait держит паузу', () => {
        const runner = new CutsceneRunner();
        const order: string[] = [];
        runner.play([
            { kind: 'call', fn: () => order.push('a') },
            { kind: 'wait', seconds: 0.5 },
            { kind: 'call', fn: () => order.push('b') }
        ]);
        // Первый шаг стартовал сразу, второй ещё ждёт.
        expect(order).toEqual(['a']);
        expect(runner.active).toBe(true);
        tick(runner, 0.1, 4); // 0.4с — всё ещё wait
        expect(order).toEqual(['a']);
        tick(runner, 0.2, 1); // 0.6с — wait кончился
        expect(order).toEqual(['a', 'b']);
        expect(runner.active).toBe(false);
    });

    it('шаг без seconds параллелен: следующий стартует сразу', () => {
        const runner = new CutsceneRunner();
        const order: string[] = [];
        runner.play([
            { kind: 'burst', fn: () => order.push('burst') },
            { kind: 'call', fn: () => order.push('call') }
        ]);
        // Шаги без длительности не блокируют: оба стартовали в том же тике.
        expect(order).toEqual(['burst', 'call']);
        expect(runner.active).toBe(false);
    });

    it('cameraMove плавно ведёт камеру к точке', () => {
        const runner = new CutsceneRunner();
        const cam = cameraAt(0, 0);
        runner.play([{ kind: 'cameraMove', x: 10, y: -20, seconds: 1, camera: cam }]);
        tick(runner, 0.25, 2); // половина пути
        expect(cam.x).toBeGreaterThan(0);
        expect(cam.x).toBeLessThan(10);
        expect(cam.y).toBeLessThan(0);
        tick(runner, 0.25, 3); // время вышло — точно в точке
        expect(cam.x).toBe(10);
        expect(cam.y).toBe(-20);
        expect(runner.active).toBe(false);
    });

    it('setFlag поднимает флаги, onComplete вызывается в конце', () => {
        const runner = new CutsceneRunner();
        const state = new GameState();
        let done = 0;
        runner.onComplete = () => done++;
        runner.play([
            { kind: 'setFlag', flag: 'flag1', state },
            { kind: 'setFlag', flag: 'flag2', state }
        ]);
        expect(state.hasFlag('flag1')).toBe(true);
        expect(state.hasFlag('flag2')).toBe(true);
        expect(done).toBe(1);
    });

    it('onStep наблюдает порядок шагов', () => {
        const seen: string[] = [];
        const runner = new CutsceneRunner((s) => seen.push(s.kind));
        runner.play([
            { kind: 'call', fn: () => undefined, seconds: 0.1 },
            { kind: 'wait', seconds: 0.1 }
        ]);
        // Первый шаг стартовал; второй — после его длительности.
        expect(seen).toEqual(['call']);
        tick(runner, 0.2, 1);
        expect(seen).toEqual(['call', 'wait']);
    });
});