/**
 * SVG content validator to detect XSS attacks in SVG files
 * SVG files are XML-based and can contain embedded JavaScript
 */

export class SVGContentValidator {
  /**
   * Check if content contains SVG with embedded scripts
   * @param content - File content as string or buffer
   * @returns True if malicious scripts are detected
   */
  static containsMaliciousScripts(content: string | Buffer): boolean {
    const contentStr = typeof content === 'string' ? content : content.toString('utf-8');

    // Check for script tags
    if (/<script[\s>]/i.test(contentStr)) {
      return true;
    }

    // Check for event handlers (onclick, onload, etc.)
    if (/on\w+\s*=/i.test(contentStr)) {
      return true;
    }

    // Check for javascript: protocol
    if (/javascript:/i.test(contentStr)) {
      return true;
    }

    // Check for data: protocol (can be used for XSS)
    if (/data:text\/html/i.test(contentStr)) {
      return true;
    }

    // Check for vbscript: protocol
    if (/vbscript:/i.test(contentStr)) {
      return true;
    }

    // Check for iframe tags
    if (/<iframe[\s>]/i.test(contentStr)) {
      return true;
    }

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

    // Check for style tags with expressions
    if (/<style[\s>][\s\S]*?expression\s*\(/i.test(contentStr)) {
      return true;
    }

    return false;
  }

  /**
   * Validate SVG file for XSS threats
   * @param buffer - File buffer (Buffer or Uint8Array)
   * @param fileName - File name for context
   * @returns Validation result
   */
  static validateSVGContent(
    buffer: Buffer | Uint8Array,
    fileName: string
  ): { isValid: boolean; error?: string } {
    try {
      // Check if it's valid UTF-8 (SVG should be text-based)
      let content: string;
      if (buffer instanceof Uint8Array) {
        content = new TextDecoder().decode(buffer);
      } else {
        content = (buffer as Buffer).toString('utf-8');
      }

      // Check for malicious scripts
      if (this.containsMaliciousScripts(content)) {
        return {
          isValid: false,
          error: `SVG file contains potentially malicious scripts or event handlers`,
        };
      }

      // Check if it's valid XML
      if (!this.isValidXML(content)) {
        return {
          isValid: false,
          error: `SVG file is not valid XML`,
        };
      }

      return { isValid: true };
    } catch (error) {
      return {
        isValid: false,
        error: `Failed to validate SVG content: ${error instanceof Error ? error.message : 'Unknown error'}`,
      };
    }
  }

  /**
   * Check if content is valid XML
   * @param content - XML content as string
   * @returns True if valid XML
   */
  private static isValidXML(content: string): boolean {
    try {
      // Basic XML validation - check for matching tags
      const openTags = (content.match(/<[^/][^>]*>/g) || []).length;
      const closeTags = (content.match(/<\/[^>]*>/g) || []).length;

      // Should have at least one root element
      return openTags > 0 && closeTags > 0;
    } catch {
      return false;
    }
  }

  /**
   * Sanitize SVG by removing potentially dangerous elements
   * @param buffer - SVG file buffer
   * @returns Sanitized SVG content
   */
  static sanitizeSVG(buffer: Buffer): Buffer {
    let content = buffer.toString('utf-8');

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

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

    // Remove javascript: protocol
    content = content.replace(/javascript:/gi, '');

    // Remove data:text/html protocol
    content = content.replace(/data:text\/html/gi, '');

    // Remove vbscript: protocol
    content = content.replace(/vbscript:/gi, '');

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

    // Remove object/embed tags
    content = content.replace(/<(object|embed)[^>]*>/gi, '');

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