import { describe, test, expect } from 'vitest';
import { VideoBlock } from './VideoBlock';

const toHtml = (VideoBlock as any).toHtml;

function embedSrc(videoUrl: string): string {
  const { html } = toHtml({ videoUrl }, '');
  const m = html.match(/<iframe src="([^"]+)"/) || html.match(/<video src="([^"]+)"/);
  return m ? m[1].replace(/&amp;/g, '&') : '';
}

describe('VideoBlock URL parsing (D4)', () => {
  test('youtube.com/watch?v=ID (existing case) resolves to embed URL', () => {
    expect(embedSrc('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toContain('youtube.com/embed/dQw4w9WgXcQ');
  });

  test('youtu.be/ID resolves to embed URL', () => {
    expect(embedSrc('https://youtu.be/dQw4w9WgXcQ')).toContain('youtube.com/embed/dQw4w9WgXcQ');
  });

  test('youtube.com/embed/ID (existing case) resolves to embed URL', () => {
    expect(embedSrc('https://www.youtube.com/embed/dQw4w9WgXcQ')).toContain('youtube.com/embed/dQw4w9WgXcQ');
  });

  test('youtube.com/shorts/ID resolves to embed URL', () => {
    expect(embedSrc('https://www.youtube.com/shorts/dQw4w9WgXcQ')).toContain('youtube.com/embed/dQw4w9WgXcQ');
  });

  test('youtube.com/live/ID resolves to embed URL', () => {
    expect(embedSrc('https://www.youtube.com/live/dQw4w9WgXcQ')).toContain('youtube.com/embed/dQw4w9WgXcQ');
  });

  test('youtube.com/watch?...&v=ID (v not first param) resolves to embed URL', () => {
    expect(embedSrc('https://www.youtube.com/watch?list=PLxyz&v=dQw4w9WgXcQ&index=3')).toContain('youtube.com/embed/dQw4w9WgXcQ');
  });

  test('vimeo.com/ID (existing case) resolves to player URL', () => {
    expect(embedSrc('https://vimeo.com/123456789')).toContain('https://player.vimeo.com/video/123456789');
  });

  test('vimeo.com/ID/HASH (private video) resolves to player URL with hash param', () => {
    const src = embedSrc('https://vimeo.com/123456789/abcdef1234');
    expect(src).toContain('https://player.vimeo.com/video/123456789');
    expect(src).toContain('h=abcdef1234');
  });

  test('direct .mp4 file still works', () => {
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4' }, '');
    expect(html).toContain('<video src="https://example.com/clip.mp4"');
  });

  test('unrecognized URL yields no output (type "none")', () => {
    const { html } = toHtml({ videoUrl: 'not-a-real-video-url' }, '');
    expect(html).toBe('');
  });

  test('emitted src is safeUrl-wrapped: javascript: scheme never reaches output', () => {
    const { html } = toHtml({ videoUrl: 'javascript:alert(1)' }, '');
    expect(html).not.toContain('javascript:');
  });
});

describe('VideoBlock.toHtml iframe accessibility (F2.4)', () => {
  test('normal-mode YouTube/Vimeo iframe has a title attribute', () => {
    const { html } = toHtml({ videoUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' }, '');
    expect(html).toMatch(/<iframe[^>]*title="[^"]+"/);
  });

  test('background-mode YouTube/Vimeo iframe has a title attribute', () => {
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789', isBackground: true }, '');
    expect(html).toMatch(/<iframe[^>]*title="[^"]+"/);
  });
});

describe('VideoBlock.toHtml overlay/innerMaxWidth XSS hardening (background mode)', () => {
  test('a malicious overlayColor cannot break out of the overlay style attribute', () => {
    const malicious = 'red" onmouseover="alert(1)';
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789', isBackground: true, overlayColor: malicious }, '');
    expect(html).not.toContain('onmouseover="alert(1)"');
  });

  test('a wrong-typed overlayOpacity (string, not number) cannot break out of the overlay style attribute', () => {
    const malicious = '50" onmouseover="alert(1)' as any;
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789', isBackground: true, overlayOpacity: malicious }, '');
    expect(html).not.toContain('onmouseover="alert(1)"');
  });

  test('a malicious innerMaxWidth cannot break out of the inner style attribute', () => {
    const malicious = '1200px" onmouseover="alert(1)';
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789', isBackground: true, innerMaxWidth: malicious }, '');
    expect(html).not.toContain('onmouseover="alert(1)"');
  });

  test('a malicious style.borderRadius cannot break out of the style attribute (normal mode, iframe wrapper)', () => {
    const malicious = { borderRadius: '8px" onmouseover="alert(1)' } as any;
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789', style: malicious }, '');
    expect(html).not.toContain('onmouseover="alert(1)"');
  });

  test('a malicious style.borderRadius cannot break out of the style attribute (direct file <video>)', () => {
    const malicious = { borderRadius: '8px" onmouseover="alert(1)' } as any;
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4', style: malicious }, '');
    expect(html).not.toContain('onmouseover="alert(1)"');
  });
});

describe('VideoBlock.toHtml iframe src ampersand encoding (F-export review Minor)', () => {
  test('embed params joined with literal & are HTML-entity-encoded in the emitted src attribute', () => {
    // autoplay+muted+controls=false forces buildEmbedParams to concatenate
    // multiple query params onto the URL with literal `&`s.
    const { html } = toHtml(
      { videoUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', autoplay: true, muted: true, controls: false },
      ''
    );
    const srcMatch = html.match(/<iframe src="([^"]+)"/);
    expect(srcMatch).toBeTruthy();
    expect(srcMatch![1]).toMatch(/&amp;/);
    expect(srcMatch![1]).not.toMatch(/&(?!amp;)/);
  });
});

describe('VideoBlock.toHtml size + aspect ratio (frame honors style props, not a hardcoded 16:9)', () => {
  test('direct file: style.width flows to the wrapper, style.aspectRatio flows to the <video>', () => {
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4', style: { width: '50%', aspectRatio: '4 / 3' } }, '');
    expect(html).toMatch(/<div style="[^"]*width:50%[^"]*"/);
    expect(html).toMatch(/<video[^>]*style="[^"]*aspect-ratio:4 \/ 3[^"]*"/);
  });

  test('direct file: no aspectRatio set -- no aspect-ratio declaration is forced onto the <video>', () => {
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4' }, '');
    const videoTag = html.match(/<video[^>]*>/)![0];
    expect(videoTag).not.toContain('aspect-ratio');
  });

  test('YouTube/Vimeo: style.aspectRatio overrides the 16:9 default on the iframe container', () => {
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789', style: { aspectRatio: '1 / 1' } }, '');
    expect(html).toMatch(/<div[^>]*style="[^"]*aspect-ratio:1 \/ 1[^"]*"[^>]*><iframe/);
  });

  test('YouTube/Vimeo: defaults to 16 / 9 when no aspectRatio style is set', () => {
    const { html } = toHtml({ videoUrl: 'https://vimeo.com/123456789' }, '');
    expect(html).toMatch(/<div[^>]*style="[^"]*aspect-ratio:16 \/ 9[^"]*"[^>]*><iframe/);
  });
});

describe('VideoBlock.toHtml poster + preload (file type)', () => {
  test('poster attribute is emitted (escaped) and preload="metadata" is always present on a direct file', () => {
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4', poster: 'https://example.com/poster.jpg' }, '');
    expect(html).toContain('poster="https://example.com/poster.jpg"');
    expect(html).toContain('preload="metadata"');
  });

  test('no poster prop -- no poster attribute is emitted, but preload="metadata" still is', () => {
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4' }, '');
    expect(html).not.toContain('poster=');
    expect(html).toContain('preload="metadata"');
  });

  test('a malicious poster (javascript: scheme) is blocked by safeImageUrl', () => {
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4', poster: 'javascript:alert(1)' }, '');
    expect(html).not.toContain('javascript:');
  });

  test('a poster value cannot break out of the poster attribute', () => {
    const malicious = 'https://example.com/x.jpg" onerror="alert(1)';
    const { html } = toHtml({ videoUrl: 'https://example.com/clip.mp4', poster: malicious }, '');
    expect(html).not.toContain('onerror="alert(1)"');
  });
});

describe('VideoBlock.craft.props exposes the box-model/animation/visibility rollout', () => {
  test('poster, animation, animationDelay, hideOnDesktop/Tablet/Mobile are present with blank/false defaults', () => {
    const props = (VideoBlock as any).craft.props;
    expect(props.poster).toBe('');
    expect(props.animation).toBe('');
    expect(props.animationDelay).toBe('0');
    expect(props.hideOnDesktop).toBe(false);
    expect(props.hideOnTablet).toBe(false);
    expect(props.hideOnMobile).toBe(false);
  });

  test('style carries blank/default box-model + size/aspect keys', () => {
    const style = (VideoBlock as any).craft.props.style;
    expect(style).toHaveProperty('width');
    expect(style).toHaveProperty('aspectRatio');
    expect(style).toHaveProperty('marginTop');
    expect(style).toHaveProperty('paddingTop');
    expect(style.border).toBe('none');
    expect(style.boxShadow).toBe('none');
    expect(style.opacity).toBe('1');
  });
});
