import { describe, expect, it } from 'vitest';
import { normalizeScenes, VideoTimelineCompileError } from '@/lib/video-export';
import { act, quiz, slide, speech, spotlight } from './helpers';

describe('normalizeScenes — ordering', () => {
  it('orders scenes by `order`, tie-broken by input index (stable)', () => {
    const scenes = [
      slide('c', [], { order: 2 }),
      slide('a', [], { order: 1 }),
      slide('b', [], { order: 1 }),
    ];
    const { scenes: out } = normalizeScenes(scenes);
    expect(out.map((s) => s.id)).toEqual(['a', 'b', 'c']);
  });

  it('falls back to input index when `order` is absent, preserving input order', () => {
    const scenes = [
      { ...slide('x', []), order: undefined },
      { ...slide('y', []), order: undefined },
    ];
    const { scenes: out } = normalizeScenes(scenes as never);
    expect(out.map((s) => s.id)).toEqual(['x', 'y']);
  });

  it('throws on an empty scene list', () => {
    expect(() => normalizeScenes([])).toThrow(VideoTimelineCompileError);
  });
});

describe('normalizeScenes — action validation', () => {
  it('drops an unknown action type with an unknown-action diagnostic', () => {
    const scenes = [slide('s', [act({ id: 'bad', type: 'teleport' }), speech('ok', 'hi')])];
    const { scenes: out, diagnostics } = normalizeScenes(scenes);
    expect(out[0].actions).toHaveLength(1);
    expect(out[0].actions?.[0].id).toBe('ok');
    expect(diagnostics).toEqual([
      expect.objectContaining({ code: 'unknown-action', sceneId: 's', actionId: 'bad' }),
    ]);
  });

  it('drops an action missing a required field with an invalid-action diagnostic', () => {
    // spotlight without elementId
    const scenes = [slide('s', [act({ id: 'sp', type: 'spotlight' }), spotlight('good', 'e1')])];
    const { scenes: out, diagnostics } = normalizeScenes(scenes);
    expect(out[0].actions?.map((a) => a.id)).toEqual(['good']);
    expect(diagnostics[0]).toMatchObject({ code: 'invalid-action', actionId: 'sp' });
  });

  it('keeps an empty-text speech (a legal dwell beat)', () => {
    const { scenes: out, diagnostics } = normalizeScenes([slide('s', [speech('e', '')])]);
    expect(out[0].actions).toHaveLength(1);
    expect(diagnostics).toHaveLength(0);
  });

  it('does not mutate the input scenes', () => {
    const scenes = [slide('b', [], { order: 2 }), slide('a', [], { order: 1 })];
    normalizeScenes(scenes);
    expect(scenes.map((s) => s.id)).toEqual(['b', 'a']);
  });

  it('validates quiz scene actions too', () => {
    const { diagnostics } = normalizeScenes([quiz('q', [act({ id: 'z', type: 'nope' })])]);
    expect(diagnostics[0].code).toBe('unknown-action');
  });
});