/**
 * Tests for video embed URL allowlist validation
 *
 * Security: Only YouTube and Vimeo embeds are allowed.
 * No arbitrary iframes or data URIs.
 */
import { describe, it, expect } from 'vitest';

import {
  validateVideoEmbed,
  parseVideoUrl,
  buildSafeEmbedUrl,
  VIDEO_PROVIDERS,
} from '../utils/videoEmbed';

describe('Video Embed Validation', () => {
  describe('VIDEO_PROVIDERS', () => {
    it('should define YouTube provider', () => {
      expect(VIDEO_PROVIDERS.youtube).toBeDefined();
      expect(VIDEO_PROVIDERS.youtube.name).toBe('YouTube');
      expect(VIDEO_PROVIDERS.youtube.patterns).toBeDefined();
      expect(VIDEO_PROVIDERS.youtube.embedTemplate).toBeDefined();
    });

    it('should define Vimeo provider', () => {
      expect(VIDEO_PROVIDERS.vimeo).toBeDefined();
      expect(VIDEO_PROVIDERS.vimeo.name).toBe('Vimeo');
      expect(VIDEO_PROVIDERS.vimeo.patterns).toBeDefined();
      expect(VIDEO_PROVIDERS.vimeo.embedTemplate).toBeDefined();
    });
  });

  describe('validateVideoEmbed', () => {
    describe('YouTube URLs', () => {
      it('should accept standard YouTube watch URLs', () => {
        const result = validateVideoEmbed('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('youtube');
        expect(result.videoId).toBe('dQw4w9WgXcQ');
      });

      it('should accept YouTube short URLs', () => {
        const result = validateVideoEmbed('https://youtu.be/dQw4w9WgXcQ');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('youtube');
        expect(result.videoId).toBe('dQw4w9WgXcQ');
      });

      it('should accept YouTube embed URLs', () => {
        const result = validateVideoEmbed('https://www.youtube.com/embed/dQw4w9WgXcQ');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('youtube');
        expect(result.videoId).toBe('dQw4w9WgXcQ');
      });

      it('should accept YouTube nocookie embed URLs', () => {
        const result = validateVideoEmbed('https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('youtube');
        expect(result.videoId).toBe('dQw4w9WgXcQ');
      });

      it('should handle YouTube URLs with extra params', () => {
        const result = validateVideoEmbed('https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=60s');
        expect(result.isValid).toBe(true);
        expect(result.videoId).toBe('dQw4w9WgXcQ');
      });

      it('should reject invalid YouTube video IDs', () => {
        const result = validateVideoEmbed('https://www.youtube.com/watch?v=');
        expect(result.isValid).toBe(false);
      });
    });

    describe('Vimeo URLs', () => {
      it('should accept standard Vimeo URLs', () => {
        const result = validateVideoEmbed('https://vimeo.com/123456789');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('vimeo');
        expect(result.videoId).toBe('123456789');
      });

      it('should accept Vimeo player URLs', () => {
        const result = validateVideoEmbed('https://player.vimeo.com/video/123456789');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('vimeo');
        expect(result.videoId).toBe('123456789');
      });

      it('should accept Vimeo URLs with hash for private videos', () => {
        const result = validateVideoEmbed('https://vimeo.com/123456789/abc123def456');
        expect(result.isValid).toBe(true);
        expect(result.provider).toBe('vimeo');
        expect(result.videoId).toBe('123456789');
        expect(result.hash).toBe('abc123def456');
      });

      it('should reject non-numeric Vimeo IDs', () => {
        const result = validateVideoEmbed('https://vimeo.com/not-a-video-id');
        expect(result.isValid).toBe(false);
      });
    });

    describe('Invalid URLs', () => {
      it('should reject arbitrary URLs', () => {
        const result = validateVideoEmbed('https://evil-site.com/embed');
        expect(result.isValid).toBe(false);
        expect(result.error).toBeDefined();
      });

      it('should reject data URIs', () => {
        const result = validateVideoEmbed('data:text/html,<script>alert("xss")</script>');
        expect(result.isValid).toBe(false);
      });

      it('should reject javascript URLs', () => {
        const result = validateVideoEmbed('javascript:alert("xss")');
        expect(result.isValid).toBe(false);
      });

      it('should reject HTTP (non-HTTPS) URLs', () => {
        const result = validateVideoEmbed('http://www.youtube.com/watch?v=dQw4w9WgXcQ');
        expect(result.isValid).toBe(false);
        expect(result.error).toContain('HTTPS');
      });

      it('should reject empty URLs', () => {
        const result = validateVideoEmbed('');
        expect(result.isValid).toBe(false);
      });

      it('should reject null/undefined', () => {
        expect(validateVideoEmbed(null as unknown as string).isValid).toBe(false);
        expect(validateVideoEmbed(undefined as unknown as string).isValid).toBe(false);
      });

      it('should reject URLs with XSS payloads', () => {
        const result = validateVideoEmbed('https://www.youtube.com/watch?v=<script>alert(1)</script>');
        expect(result.isValid).toBe(false);
      });

      it('should reject Dailymotion (not in allowlist)', () => {
        const result = validateVideoEmbed('https://www.dailymotion.com/video/x123456');
        expect(result.isValid).toBe(false);
      });
    });
  });

  describe('parseVideoUrl', () => {
    it('should extract video ID from YouTube watch URL', () => {
      const parsed = parseVideoUrl('https://www.youtube.com/watch?v=abc123XYZ');
      expect(parsed?.provider).toBe('youtube');
      expect(parsed?.videoId).toBe('abc123XYZ');
    });

    it('should extract video ID from youtu.be URL', () => {
      const parsed = parseVideoUrl('https://youtu.be/abc123XYZ');
      expect(parsed?.provider).toBe('youtube');
      expect(parsed?.videoId).toBe('abc123XYZ');
    });

    it('should extract video ID from Vimeo URL', () => {
      const parsed = parseVideoUrl('https://vimeo.com/987654321');
      expect(parsed?.provider).toBe('vimeo');
      expect(parsed?.videoId).toBe('987654321');
    });

    it('should return null for invalid URLs', () => {
      expect(parseVideoUrl('not a url')).toBeNull();
      expect(parseVideoUrl('')).toBeNull();
    });
  });

  describe('buildSafeEmbedUrl', () => {
    it('should build YouTube embed URL', () => {
      const url = buildSafeEmbedUrl('youtube', 'dQw4w9WgXcQ');
      expect(url).toBe('https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ');
    });

    it('should build Vimeo embed URL', () => {
      const url = buildSafeEmbedUrl('vimeo', '123456789');
      expect(url).toBe('https://player.vimeo.com/video/123456789');
    });

    it('should include hash for private Vimeo videos', () => {
      const url = buildSafeEmbedUrl('vimeo', '123456789', 'abc123');
      expect(url).toBe('https://player.vimeo.com/video/123456789?h=abc123');
    });

    it('should sanitize video ID to prevent injection', () => {
      const url = buildSafeEmbedUrl('youtube', 'abc"><script>');
      // Should only include alphanumeric and safe characters
      expect(url).not.toContain('<script>');
      expect(url).not.toContain('"');
    });

    it('should throw for unknown provider', () => {
      expect(() => buildSafeEmbedUrl('unknown' as never, '123')).toThrow();
    });
  });

  describe('Security Edge Cases', () => {
    it('should reject URLs with encoded XSS', () => {
      const result = validateVideoEmbed('https://www.youtube.com/watch?v=%3Cscript%3Ealert(1)%3C/script%3E');
      expect(result.isValid).toBe(false);
    });

    it('should reject URLs with unicode tricks', () => {
      // Using homograph attack with unicode lookalikes
      const result = validateVideoEmbed('https://www.youtube\u0430.com/watch?v=abc123'); // Cyrillic 'a'
      expect(result.isValid).toBe(false);
    });

    it('should reject URLs with null bytes', () => {
      const result = validateVideoEmbed('https://www.youtube.com/watch?v=abc\x00123');
      expect(result.isValid).toBe(false);
    });

    it('should validate video ID format strictly', () => {
      // YouTube IDs are 11 characters, alphanumeric + - and _
      const validYouTube = validateVideoEmbed('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
      expect(validYouTube.isValid).toBe(true);

      const tooShort = validateVideoEmbed('https://www.youtube.com/watch?v=abc');
      expect(tooShort.isValid).toBe(false);

      const invalidChars = validateVideoEmbed('https://www.youtube.com/watch?v=abc!@#$%^&*()');
      expect(invalidChars.isValid).toBe(false);
    });
  });
});
