import { describe, expect, it } from 'vitest';
import { compileVideoTimeline, VideoTimelineSchema } from '@/lib/video-export';
import { NO_ASSETS, NO_PROBE, interactive, speech, stubInteractiveHtml } from './helpers';
import { quizScrollScene } from './quiz-scroll-fixture';

describe('compileVideoTimeline — static interactive HTML', () => {
  it('promotes prepared HTML to a supported base and plans its asset', () => {
    const ir = compileVideoTimeline(
      {
        stage: { id: 'stage', name: 'Interactive' },
        scenes: [interactive('widget', '<!doctype html><h1>Widget</h1>')],
      },
      {
        timing: NO_PROBE,
        assets: NO_ASSETS,
        interactive: stubInteractiveHtml({
          widget: {
            id: 'interactive:widget',
            present: true,
            contentHash: 'a'.repeat(64),
          },
        }),
      },
    );

    expect(() => VideoTimelineSchema.parse(ir)).not.toThrow();
    expect(ir.scenes[0]).toMatchObject({
      supported: true,
      base: {
        kind: 'interactive-html',
        assetId: 'interactive:widget',
        assetRef: 'interactive/001-widget.html',
        contentHash: 'a'.repeat(64),
        readyTimeoutMs: 8000,
        settleMs: 250,
      },
    });
    expect(ir.assets.entries).toContainEqual({
      assetId: 'interactive:widget',
      kind: 'html',
      path: 'interactive/001-widget.html',
      present: true,
    });
    expect(ir.diagnostics).toContainEqual(
      expect.objectContaining({ code: 'interactive-static-html', sceneId: 'widget' }),
    );
    expect(ir.diagnostics).not.toContainEqual(
      expect.objectContaining({ code: 'unsupported-scene', sceneId: 'widget' }),
    );
  });

  it('uses the existing placeholder for missing embedded HTML', () => {
    const ir = compileVideoTimeline(
      {
        stage: { id: 'stage', name: 'Interactive' },
        scenes: [interactive('missing', '')],
      },
      { timing: NO_PROBE, assets: NO_ASSETS },
    );

    expect(ir.scenes[0]).toMatchObject({
      supported: false,
      base: { kind: 'placeholder', reason: expect.stringContaining('missing') },
    });
    expect(ir.diagnostics).toContainEqual(
      expect.objectContaining({ code: 'missing-interactive-html', sceneId: 'missing' }),
    );
  });

  it('surfaces unresolved resources and falls back without failing compile', () => {
    const ir = compileVideoTimeline(
      {
        stage: { id: 'stage', name: 'Interactive' },
        scenes: [interactive('remote', '<img src="https://example.test/a.png">')],
      },
      {
        timing: NO_PROBE,
        assets: NO_ASSETS,
        interactive: stubInteractiveHtml({
          remote: {
            id: 'interactive:remote',
            present: false,
            failure: 'unresolved-resource',
            message: 'Interactive HTML has unresolved resources: https://example.test/a.png.',
          },
        }),
      },
    );

    expect(ir.scenes[0].base).toMatchObject({
      kind: 'placeholder',
      reason: expect.stringContaining('unresolved resources'),
    });
    expect(ir.diagnostics).toContainEqual(
      expect.objectContaining({ code: 'unresolved-interactive-resource', sceneId: 'remote' }),
    );
  });

  it('keeps static interactive first-class while a preceding Quiz shifts all later timing', () => {
    const quiz = quizScrollScene(0);
    const widget = interactive(
      'widget-after-quiz',
      '<!doctype html><h1>Widget after Quiz</h1>',
      [speech('widget-narration', 'The interactive scene follows the extended Quiz.')],
      1,
    );
    const interactiveSource = stubInteractiveHtml({
      'widget-after-quiz': {
        id: 'interactive:widget-after-quiz',
        present: true,
        contentHash: 'b'.repeat(64),
      },
    });
    const baseline = compileVideoTimeline(
      { stage: { id: 'stage', name: 'Integrated export' }, scenes: [quiz, widget] },
      { timing: NO_PROBE, assets: NO_ASSETS, interactive: interactiveSource },
    );
    const ir = compileVideoTimeline(
      { stage: { id: 'stage', name: 'Integrated export' }, scenes: [quiz, widget] },
      {
        timing: NO_PROBE,
        assets: NO_ASSETS,
        interactive: interactiveSource,
        quizLayout: {
          measureQuestionList: () => ({
            contentHeightPx: 1_200,
            viewportHeightPx: 480,
            frameHeightPx: 720,
          }),
        },
      },
    );
    const list = ir.scenes[0].visuals.find((visual) => visual.kind === 'quiz-question-list');
    if (!list || list.kind !== 'quiz-question-list') throw new Error('Quiz list not planned');

    expect(ir.version).toBe(4);
    expect(() => VideoTimelineSchema.parse(ir)).not.toThrow();
    expect(ir.scenes[1]).toMatchObject({
      startMs: baseline.scenes[1].startMs + list.durationMs,
      supported: true,
      base: {
        kind: 'interactive-html',
        assetRef: 'interactive/002-widget-after-quiz.html',
      },
    });
    expect(ir.scenes[1].narration[0].startMs).toBe(
      baseline.scenes[1].narration[0].startMs + list.durationMs,
    );
    expect(ir.subtitles.find((cue) => cue.sceneId === widget.id)?.startMs).toBe(
      baseline.subtitles.find((cue) => cue.sceneId === widget.id)!.startMs + list.durationMs,
    );
    expect(ir.totalDurationMs).toBe(baseline.totalDurationMs + list.durationMs);
  });
});