/**
 * XSS vulnerability detection and analysis
 */

/**
 * Types of XSS vulnerabilities
 */
export enum XssVulnerabilityType {
  REFLECTED = 'reflected',
  STORED = 'stored',
  DOM_BASED = 'dom-based',
  TEMPLATE_INJECTION = 'template-injection',
}

/**
 * Severity levels for vulnerabilities
 */
export enum VulnerabilitySeverity {
  LOW = 'low',
  MEDIUM = 'medium',
  HIGH = 'high',
  CRITICAL = 'critical',
}

/**
 * XSS vulnerability detection result
 */
export interface XssVulnerability {
  type: XssVulnerabilityType;
  severity: VulnerabilitySeverity;
  description: string;
  location: string;
  payload: string;
  recommendation: string;
}

/**
 * Common XSS attack patterns
 */
const XSS_PATTERNS = [
  // Script tags
  /<script[^>]*>.*?<\/script>/gi,
  /<script[^>]*>/gi,

  // Event handlers
  /on\w+\s*=\s*['"]/gi,

  // JavaScript URLs
  /javascript\s*:/gi,

  // Data URLs with JavaScript
  /data\s*:\s*text\/html/gi,

  // SVG with script
  /<svg[^>]*>.*?<\/svg>/gi,

  // Object/embed tags
  /<(object|embed|applet)[^>]*>/gi,

  // Meta refresh
  /<meta[^>]*http-equiv\s*=\s*['"]\s*refresh/gi,

  // Link with JavaScript
  /<link[^>]*href\s*=\s*['"]\s*javascript/gi,

  // Style with expression
  /expression\s*\(/gi,

  // Import statements
  /@import/gi,
];

/**
 * Dangerous HTML attributes that can execute JavaScript
 */
const DANGEROUS_ATTRIBUTES = [
  'onabort', 'onblur', 'onchange', 'onclick', 'ondblclick', 'onerror',
  'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown',
  'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset',
  'onresize', 'onselect', 'onsubmit', 'onunload', 'onafterprint',
  'onbeforeprint', 'onbeforeunload', 'onhashchange', 'onmessage',
  'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate',
  'onstorage', 'oncontextmenu', 'oninput', 'oninvalid', 'onsearch',
];

/**
 * XSS vulnerability detector
 */
export class XssVulnerabilityDetector {
  private patterns: RegExp[];
  private dangerousAttributes: string[];

  /**
   * Create a new XSS vulnerability detector
   */
  constructor() {
    this.patterns = [...XSS_PATTERNS];
    this.dangerousAttributes = [...DANGEROUS_ATTRIBUTES];
  }

  /**
   * Scan content for potential XSS vulnerabilities
   * @param content Content to scan
   * @param location Location identifier for the content
   * @returns Array of detected vulnerabilities
   */
  scanContent(content: string, location: string = 'unknown'): XssVulnerability[] {
    const vulnerabilities: XssVulnerability[] = [];

    // Check for script injection patterns
    for (const pattern of this.patterns) {
      const matches = content.match(pattern);
      if (matches) {
        for (const match of matches) {
          vulnerabilities.push({
            type: this.determineVulnerabilityType(match),
            severity: this.determineSeverity(match),
            description: `Potential XSS vulnerability detected: ${match.substring(0, 100)}...`,
            location,
            payload: match,
            recommendation: this.getRecommendation(match),
          });
        }
      }
    }

    // Check for dangerous attributes
    for (const attr of this.dangerousAttributes) {
      const attrPattern = new RegExp(`${attr}\\s*=`, 'gi');
      if (attrPattern.test(content)) {
        vulnerabilities.push({
          type: XssVulnerabilityType.DOM_BASED,
          severity: VulnerabilitySeverity.HIGH,
          description: `Dangerous event handler attribute detected: ${attr}`,
          location,
          payload: attr,
          recommendation: 'Remove event handler attributes and use proper event listeners instead.',
        });
      }
    }

    return vulnerabilities;
  }

  /**
   * Check if a string contains potential XSS payload
   * @param input Input string to check
   * @returns True if potential XSS is detected
   */
  containsXss(input: string): boolean {
    return this.patterns.some(pattern => pattern.test(input)) ||
           this.dangerousAttributes.some(attr =>
             new RegExp(`${attr}\\s*=`, 'gi').test(input)
           );
  }

  /**
   * Analyze template for potential injection vulnerabilities
   * @param template Template string
   * @param variables Variables used in template
   * @returns Array of vulnerabilities
   */
  analyzeTemplate(template: string, variables: Record<string, unknown> = {}): XssVulnerability[] {
    const vulnerabilities: XssVulnerability[] = [];

    // Check for unescaped variable interpolation
    const interpolationPattern = /\$\{([^}]+)\}/g;
    let match;

    while ((match = interpolationPattern.exec(template)) !== null) {
      const variableName = match[1]?.trim();
      if (!variableName) continue;
      const variableValue = variables[variableName];

      if (typeof variableValue === 'string' && this.containsXss(variableValue)) {
        vulnerabilities.push({
          type: XssVulnerabilityType.TEMPLATE_INJECTION,
          severity: VulnerabilitySeverity.CRITICAL,
          description: `Unescaped variable interpolation with potential XSS: \${${variableName}}`,
          location: 'template',
          payload: String(variableValue),
          recommendation: 'Use proper HTML escaping for all template variables.',
        });
      }
    }

    return vulnerabilities;
  }

  /**
   * Determine the type of XSS vulnerability based on the payload
   * @param payload The detected payload
   * @returns Vulnerability type
   */
  private determineVulnerabilityType(payload: string): XssVulnerabilityType {
    if (payload.includes('<script')) {
      return XssVulnerabilityType.REFLECTED;
    }
    if (payload.includes('javascript:')) {
      return XssVulnerabilityType.DOM_BASED;
    }
    if (payload.includes('${') || payload.includes('{{')) {
      return XssVulnerabilityType.TEMPLATE_INJECTION;
    }
    return XssVulnerabilityType.STORED;
  }

  /**
   * Determine the severity of a vulnerability based on the payload
   * @param payload The detected payload
   * @returns Vulnerability severity
   */
  private determineSeverity(payload: string): VulnerabilitySeverity {
    if (payload.includes('<script') || payload.includes('javascript:')) {
      return VulnerabilitySeverity.CRITICAL;
    }
    if (payload.includes('on') && payload.includes('=')) {
      return VulnerabilitySeverity.HIGH;
    }
    if (payload.includes('<') || payload.includes('>')) {
      return VulnerabilitySeverity.MEDIUM;
    }
    return VulnerabilitySeverity.LOW;
  }

  /**
   * Get recommendation for fixing a vulnerability
   * @param payload The detected payload
   * @returns Recommendation string
   */
  private getRecommendation(payload: string): string {
    if (payload.includes('<script')) {
      return 'Remove script tags and use proper JavaScript loading mechanisms.';
    }
    if (payload.includes('javascript:')) {
      return 'Replace javascript: URLs with proper event handlers.';
    }
    if (payload.includes('on') && payload.includes('=')) {
      return 'Remove inline event handlers and use addEventListener instead.';
    }
    return 'Sanitize or escape the content before rendering.';
  }

  /**
   * Add a custom XSS pattern to detect
   * @param pattern Regular expression pattern
   */
  addPattern(pattern: RegExp): void {
    this.patterns.push(pattern);
  }

  /**
   * Add a custom dangerous attribute to detect
   * @param attribute Attribute name
   */
  addDangerousAttribute(attribute: string): void {
    this.dangerousAttributes.push(attribute.toLowerCase());
  }
}

/**
 * Default XSS vulnerability detector instance
 */
export const defaultXssDetector = new XssVulnerabilityDetector();
