/**
 * Video Embed Validation Utilities
 *
 * Security: Only YouTube and Vimeo embeds are allowed.
 * This module validates video URLs and builds safe embed URLs.
 */

// ============================================================================
// Video Provider Definitions
// ============================================================================

export interface VideoProvider {
  name: string;
  patterns: RegExp[];
  embedTemplate: (videoId: string, hash?: string) => string;
  validateId: (id: string) => boolean;
}

export const VIDEO_PROVIDERS: Record<string, VideoProvider> = {
  youtube: {
    name: 'YouTube',
    patterns: [
      // Standard watch URL: https://www.youtube.com/watch?v=VIDEO_ID
      /^https:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/,
      // Short URL: https://youtu.be/VIDEO_ID
      /^https:\/\/youtu\.be\/([a-zA-Z0-9_-]{11})/,
      // Embed URL: https://www.youtube.com/embed/VIDEO_ID
      /^https:\/\/(?:www\.)?youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
      // Nocookie embed: https://www.youtube-nocookie.com/embed/VIDEO_ID
      /^https:\/\/(?:www\.)?youtube-nocookie\.com\/embed\/([a-zA-Z0-9_-]{11})/,
    ],
    embedTemplate: (videoId: string) =>
      `https://www.youtube-nocookie.com/embed/${videoId}`,
    validateId: (id: string) => /^[a-zA-Z0-9_-]{11}$/.test(id),
  },
  vimeo: {
    name: 'Vimeo',
    patterns: [
      // Standard URL: https://vimeo.com/VIDEO_ID
      /^https:\/\/(?:www\.)?vimeo\.com\/(\d+)(?:\/([a-zA-Z0-9]+))?/,
      // Player URL: https://player.vimeo.com/video/VIDEO_ID
      /^https:\/\/player\.vimeo\.com\/video\/(\d+)/,
    ],
    embedTemplate: (videoId: string, hash?: string) =>
      hash
        ? `https://player.vimeo.com/video/${videoId}?h=${hash}`
        : `https://player.vimeo.com/video/${videoId}`,
    validateId: (id: string) => /^\d+$/.test(id),
  },
};

// ============================================================================
// Validation Result Types
// ============================================================================

export interface VideoValidationResult {
  isValid: boolean;
  provider?: 'youtube' | 'vimeo';
  videoId?: string;
  hash?: string;
  error?: string;
}

export interface ParsedVideo {
  provider: 'youtube' | 'vimeo';
  videoId: string;
  hash?: string;
}

// ============================================================================
// URL Sanitization
// ============================================================================

/**
 * Check if a string contains potentially dangerous content
 */
function containsDangerousContent(str: string): boolean {
  if (!str) return false;

  const dangerousPatterns = [
    /<script/i,
    /<\/script/i,
    /javascript:/i,
    /onerror=/i,
    /onload=/i,
    /onclick=/i,
    /%00/, // null byte
    /[\u0430-\u04FF]/, // Cyrillic characters (homograph attacks)
    /[\u0600-\u06FF]/, // Arabic characters
  ];

  return dangerousPatterns.some(pattern => pattern.test(str));
}

/**
 * Sanitize a video ID to prevent injection
 */
function sanitizeVideoId(id: string, provider: 'youtube' | 'vimeo'): string {
  if (provider === 'youtube') {
    // YouTube IDs: exactly 11 alphanumeric chars, plus - and _
    return id.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 11);
  }
  // Vimeo IDs: numeric only
  return id.replace(/\D/g, '');
}

// ============================================================================
// Validation Functions
// ============================================================================

/**
 * Validate a video embed URL
 *
 * @param url - The URL to validate
 * @returns Validation result with provider and video ID if valid
 */
export function validateVideoEmbed(url: string): VideoValidationResult {
  // Handle null/undefined
  if (!url || typeof url !== 'string') {
    return { isValid: false, error: 'URL is required' };
  }

  const trimmedUrl = url.trim();

  // Check for dangerous content
  if (containsDangerousContent(trimmedUrl)) {
    return { isValid: false, error: 'URL contains invalid characters' };
  }

  // Must be HTTPS
  if (!trimmedUrl.startsWith('https://')) {
    return { isValid: false, error: 'URL must use HTTPS' };
  }

  // Check for data: and javascript: protocols
  if (trimmedUrl.startsWith('data:') || trimmedUrl.includes('javascript:')) {
    return { isValid: false, error: 'Invalid URL protocol' };
  }

  // Try to parse as YouTube
  for (const pattern of VIDEO_PROVIDERS.youtube.patterns) {
    const match = trimmedUrl.match(pattern);
    if (match && match[1]) {
      const videoId = match[1];
      if (!VIDEO_PROVIDERS.youtube.validateId(videoId)) {
        return { isValid: false, error: 'Invalid YouTube video ID' };
      }
      return {
        isValid: true,
        provider: 'youtube',
        videoId,
      };
    }
  }

  // Try to parse as Vimeo
  for (const pattern of VIDEO_PROVIDERS.vimeo.patterns) {
    const match = trimmedUrl.match(pattern);
    if (match && match[1]) {
      const videoId = match[1];
      const hash = match[2];
      if (!VIDEO_PROVIDERS.vimeo.validateId(videoId)) {
        return { isValid: false, error: 'Invalid Vimeo video ID' };
      }
      return {
        isValid: true,
        provider: 'vimeo',
        videoId,
        hash,
      };
    }
  }

  // No match found
  return {
    isValid: false,
    error: 'URL must be from YouTube or Vimeo',
  };
}

/**
 * Parse a video URL to extract provider and ID
 *
 * @param url - The URL to parse
 * @returns Parsed video info or null if invalid
 */
export function parseVideoUrl(url: string): ParsedVideo | null {
  const result = validateVideoEmbed(url);
  if (result.isValid && result.provider && result.videoId) {
    return {
      provider: result.provider,
      videoId: result.videoId,
      hash: result.hash,
    };
  }
  return null;
}

/**
 * Build a safe embed URL from provider and video ID
 *
 * @param provider - The video provider
 * @param videoId - The video ID
 * @param hash - Optional hash for private Vimeo videos
 * @returns Safe embed URL
 */
export function buildSafeEmbedUrl(
  provider: 'youtube' | 'vimeo',
  videoId: string,
  hash?: string
): string {
  const providerConfig = VIDEO_PROVIDERS[provider];

  if (!providerConfig) {
    throw new Error(`Unknown video provider: ${provider}`);
  }

  // Sanitize the video ID
  const sanitizedId = sanitizeVideoId(videoId, provider);

  // Validate the sanitized ID
  if (!providerConfig.validateId(sanitizedId)) {
    throw new Error(`Invalid video ID for ${provider}`);
  }

  // Sanitize hash if present (for Vimeo)
  const sanitizedHash = hash ? hash.replace(/[^a-zA-Z0-9]/g, '') : undefined;

  return providerConfig.embedTemplate(sanitizedId, sanitizedHash);
}

/**
 * Get the embed URL from a video URL
 *
 * @param url - The video URL
 * @returns Safe embed URL or null if invalid
 */
export function getEmbedUrl(url: string): string | null {
  const parsed = parseVideoUrl(url);
  if (!parsed) return null;

  try {
    return buildSafeEmbedUrl(parsed.provider, parsed.videoId, parsed.hash);
  } catch {
    return null;
  }
}
