/**
 * Validator for detecting XSS attacks embedded in various file types
 * Covers HTML, XML, PDF, Office documents, and other formats that can contain scripts
 */

export class EmbeddedContentValidator {
  /**
   * Check if content contains XSS attack patterns
   * @param content - File content as string, Buffer, or Uint8Array
   * @param mimeType - MIME type of the file
   * @returns True if malicious content is detected
   */
  static containsXSSPatterns(content: string | Buffer | Uint8Array, mimeType: string): boolean {
    let contentStr: string;
    if (typeof content === 'string') {
      contentStr = content;
    } else if (content instanceof Uint8Array) {
      contentStr = new TextDecoder().decode(content);
    } else {
      contentStr = (content as Buffer).toString('utf-8');
    }

    // Universal XSS patterns that apply to most file types
    const xssPatterns = [
      /<script[\s>]/i, // Script tags
      /on\w+\s*=\s*["'][^"']*["']/i, // Event handlers with quotes
      /on\w+\s*=\s*[^\s>]*/i, // Event handlers without quotes
      /javascript:/i, // JavaScript protocol
      /data:text\/html/i, // Data URI with HTML
      /vbscript:/i, // VBScript protocol
      /<iframe[\s>]/i, // iFrame tags
      /<object[\s>]/i, // Object tags
      /<embed[\s>]/i, // Embed tags
      /<applet[\s>]/i, // Applet tags
      /<meta[\s>]/i, // Meta tags (can redirect)
      /<link[\s>]/i, // Link tags (can load malicious resources)
      /<style[\s>][\s\S]*?expression\s*\(/i, // CSS expressions
      /eval\s*\(/i, // Eval function
      /expression\s*\(/i, // CSS expression
      /import\s+/i, // Import statements
      /<!--[\s\S]*?-->/i, // HTML comments (can hide code)
    ];

    for (const pattern of xssPatterns) {
      if (pattern.test(contentStr)) {
        return true;
      }
    }

    // MIME-type specific checks
    if (mimeType.includes('html') || mimeType.includes('xml')) {
      return this.checkHTMLXMLContent(contentStr);
    }

    if (mimeType.includes('pdf')) {
      return this.checkPDFContent(contentStr);
    }

    if (mimeType.includes('word') || mimeType.includes('document')) {
      return this.checkOfficeDocumentContent(contentStr);
    }

    if (mimeType.includes('sheet') || mimeType.includes('excel')) {
      return this.checkSpreadsheetContent(contentStr);
    }

    if (mimeType.includes('svg')) {
      return this.checkSVGContent(contentStr);
    }

    return false;
  }

  /**
   * Check HTML/XML content for XSS
   */
  private static checkHTMLXMLContent(content: string): boolean {
    // Check for script tags
    if (/<script[\s\S]*?<\/script>/i.test(content)) {
      return true;
    }

    // Check for event handlers
    if (/\s+on\w+\s*=/i.test(content)) {
      return true;
    }

    // Check for dangerous tags
    if (/<(iframe|object|embed|applet|meta|link|form|input|button)[\s>]/i.test(content)) {
      return true;
    }

    // Check for protocol handlers
    if (/(javascript|data|vbscript):/i.test(content)) {
      return true;
    }

    return false;
  }

  /**
   * Check PDF content for embedded XSS
   * PDFs can contain JavaScript and embedded files
   */
  private static checkPDFContent(content: string): boolean {
    // Check for JavaScript in PDF
    if (/\/JavaScript|\/JS|\/OpenAction|\/AA/i.test(content)) {
      return true;
    }

    // Check for embedded files
    if (/\/EmbeddedFile|\/ObjStm/i.test(content)) {
      return true;
    }

    // Check for launch actions
    if (/\/Launch|\/SubmitForm|\/ImportData/i.test(content)) {
      return true;
    }

    return false;
  }

  /**
   * Check Office document content for XSS
   * Office documents (DOCX, XLSX) are ZIP files containing XML
   */
  private static checkOfficeDocumentContent(content: string): boolean {
    // Check for VBA macros
    if (/vbaProject|VBA|Macro/i.test(content)) {
      return true;
    }

    // Check for embedded scripts
    if (/<script[\s\S]*?<\/script>/i.test(content)) {
      return true;
    }

    // Check for event handlers
    if (/\s+on\w+\s*=/i.test(content)) {
      return true;
    }

    // Check for external data connections
    if (/<externalData|<connection/i.test(content)) {
      return true;
    }

    return false;
  }

  /**
   * Check spreadsheet content for XSS
   */
  private static checkSpreadsheetContent(content: string): boolean {
    // Check for formulas that could execute code
    if (/=cmd\(|=powershell|=system|=exec/i.test(content)) {
      return true;
    }

    // Check for VBA macros
    if (/vbaProject|VBA|Macro/i.test(content)) {
      return true;
    }

    // Check for embedded scripts
    if (/<script[\s\S]*?<\/script>/i.test(content)) {
      return true;
    }

    return false;
  }

  /**
   * Check SVG content for XSS
   */
  private static checkSVGContent(content: string): boolean {
    // Check for script tags
    if (/<script[\s\S]*?<\/script>/i.test(content)) {
      return true;
    }

    // Check for event handlers
    if (/\s+on\w+\s*=/i.test(content)) {
      return true;
    }

    // Check for dangerous tags
    if (/<(iframe|object|embed|applet)[\s>]/i.test(content)) {
      return true;
    }

    // Check for protocol handlers
    if (/(javascript|data|vbscript):/i.test(content)) {
      return true;
    }

    return false;
  }

  /**
   * Get XSS threat level for content
   * @param content - File content as string, Buffer, or Uint8Array
   * @param mimeType - MIME type
   * @returns Threat level: 'none', 'low', 'medium', 'high', 'critical'
   */
  static getThreatLevel(content: string | Buffer | Uint8Array, mimeType: string): 'none' | 'low' | 'medium' | 'high' | 'critical' {
    let contentStr: string;
    if (typeof content === 'string') {
      contentStr = content;
    } else if (content instanceof Uint8Array) {
      contentStr = new TextDecoder().decode(content);
    } else {
      contentStr = (content as Buffer).toString('utf-8');
    }

    // Critical threats
    if (/<script[\s\S]*?<\/script>/i.test(contentStr)) {
      return 'critical';
    }

    if (/eval\s*\(/i.test(contentStr)) {
      return 'critical';
    }

    if (/\/JavaScript|\/JS|\/OpenAction/i.test(contentStr)) {
      return 'critical';
    }

    // High threats
    if (/on\w+\s*=\s*["'][^"']*["']/i.test(contentStr)) {
      return 'high';
    }

    if (/(javascript|vbscript):/i.test(contentStr)) {
      return 'high';
    }

    if (/<(iframe|object|embed|applet)[\s>]/i.test(contentStr)) {
      return 'high';
    }

    // Medium threats
    if (/data:text\/html/i.test(contentStr)) {
      return 'medium';
    }

    if (/vbaProject|VBA|Macro/i.test(contentStr)) {
      return 'medium';
    }

    // Low threats
    if (/<!--[\s\S]*?-->/i.test(contentStr)) {
      return 'low';
    }

    return 'none';
  }

  /**
   * Sanitize content by removing XSS patterns
   * WARNING: This is a basic sanitization and may not catch all attacks
   * For production, use a dedicated sanitization library
   * @param content - File content
   * @param mimeType - MIME type
   * @returns Sanitized content
   */
  static sanitizeContent(content: Buffer, mimeType: string): Buffer {
    let contentStr = content.toString('utf-8');

    // Remove script tags
    contentStr = contentStr.replace(/<script[\s\S]*?<\/script>/gi, '');

    // Remove event handlers
    contentStr = contentStr.replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, '');
    contentStr = contentStr.replace(/\s+on\w+\s*=\s*[^\s>]*/gi, '');

    // Remove dangerous protocols
    contentStr = contentStr.replace(/javascript:/gi, '');
    contentStr = contentStr.replace(/vbscript:/gi, '');
    contentStr = contentStr.replace(/data:text\/html/gi, '');

    // Remove dangerous tags
    contentStr = contentStr.replace(/<(iframe|object|embed|applet)[\s\S]*?<\/\1>/gi, '');

    return Buffer.from(contentStr, 'utf-8');
  }
}
