// HTML Smuggling Detector - Detects client-side file assembly attacks
// Browser Techniques Line 80: Blob URL file assembly
// Use Blob URLs, ArrayBuffers, atob() to create payload locally

import { BaseDetector } from '../base-detector.js';

export class HtmlSmugglingDetector extends BaseDetector {
  constructor(config = {}) {
    super({
      name: 'html-smuggling',
      category: 'code-injection',
      version: '1.0.0',
      description: 'Detects HTML smuggling attacks using Blob URLs and client-side file assembly',
      weight: 4,
      severity: 'critical',
      ...config
    });
  }

  async detect(target, ruleRegistry) {
    const findings = [];

    // This detector requires API call monitoring data from content script
    const blobCreations = target.blobCreations || [];
    const atobCalls = target.atobCalls || [];
    const downloads = target.downloads || [];
    const arrayBuffers = target.arrayBuffers || [];

    if (
      blobCreations.length === 0 &&
      atobCalls.length === 0 &&
      downloads.length === 0 &&
      arrayBuffers.length === 0
    ) {
      return this.createResult(false, [], 0);
    }

    const rules = ruleRegistry.getRules('code-injection', 'html-smuggling');

    if (!rules) {
      return this.createResult(false, [], 0);
    }

    // 1. Detect suspicious Blob URL creation
    for (const blob of blobCreations) {
      const isSuspicious = this.isSuspiciousBlob(blob, rules);

      if (isSuspicious.suspicious) {
        findings.push(this.createFinding({
          pattern: 'suspicious-blob-creation',
          matched: `Blob: ${blob.mimeType}, ${blob.size} bytes`,
          description: isSuspicious.reason,
          severity: isSuspicious.severity,
          weight: isSuspicious.weight,
          metadata: {
            blobUrl: blob.url,
            size: blob.size,
            mimeType: blob.mimeType,
            technique: 'blob-url-creation'
          }
        }));
      }
    }

    // 2. Detect large base64 decoding (likely smuggled payload)
    for (const atobCall of atobCalls) {
      if (atobCall.outputSize > (rules.atobSizeThreshold || 100000)) {
        findings.push(this.createFinding({
          pattern: 'large-atob-decode',
          matched: `${atobCall.outputSize} bytes decoded`,
          description: 'Large base64 decode operation (potential smuggled payload)',
          severity: 'high',
          weight: 4,
          metadata: {
            outputSize: atobCall.outputSize,
            technique: 'base64-smuggling'
          }
        }));
      }
    }

    // 3. Detect automatic downloads from Blob URLs
    for (const download of downloads) {
      if (download.url && download.url.startsWith('blob:')) {
        const isAutomatic = download.triggered === 'auto' || download.userInitiated === false;
        const hasExecutableExt = this.hasExecutableExtension(download.filename, rules);

        if (isAutomatic) {
          findings.push(this.createFinding({
            pattern: 'auto-blob-download',
            matched: download.filename || 'blob download',
            description: 'Automatic download from client-side assembled file',
            severity: hasExecutableExt ? 'critical' : 'high',
            weight: hasExecutableExt ? 5 : 4,
            metadata: {
              filename: download.filename,
              blobUrl: download.url,
              fileSize: download.size,
              technique: 'html-smuggling-download'
            }
          }));
        }
      }
    }

    // 4. Detect ArrayBuffer manipulation patterns
    for (const buffer of arrayBuffers) {
      if (buffer.size > (rules.arrayBufferSizeThreshold || 500000)) {
        findings.push(this.createFinding({
          pattern: 'large-array-buffer',
          matched: `ArrayBuffer: ${buffer.size} bytes`,
          description: 'Large ArrayBuffer manipulation (potential file assembly)',
          severity: 'medium',
          weight: 3,
          metadata: {
            size: buffer.size,
            operations: buffer.operations,
            technique: 'array-buffer-assembly'
          }
        }));
      }
    }

    // 5. Detect combination attack (multiple smuggling indicators)
    const indicators = [
      blobCreations.length > 0,
      atobCalls.some(c => c.outputSize > 50000),
      downloads.some(d => d.url?.startsWith('blob:')),
      arrayBuffers.some(b => b.size > 100000)
    ].filter(Boolean).length;

    if (indicators >= 3) {
      findings.push(this.createFinding({
        pattern: 'multi-indicator-smuggling',
        matched: `${indicators} HTML smuggling indicators`,
        description: 'Multiple HTML smuggling techniques detected (high confidence attack)',
        severity: 'critical',
        weight: 5,
        metadata: {
          indicatorCount: indicators,
          technique: 'advanced-html-smuggling'
        }
      }));
    }

    // 6. Detect file splitting/reassembly pattern
    if (arrayBuffers.length > 1 && blobCreations.length > 0) {
      findings.push(this.createFinding({
        pattern: 'file-reassembly',
        matched: `${arrayBuffers.length} buffers assembled`,
        description: 'File splitting and reassembly detected',
        severity: 'high',
        weight: 4,
        metadata: {
          bufferCount: arrayBuffers.length,
          blobCount: blobCreations.length,
          technique: 'split-reassembly'
        }
      }));
    }

    // 7. Detect obfuscated data URLs
    if (target.hasObfuscatedDataUrl) {
      findings.push(this.createFinding({
        pattern: 'obfuscated-data-url',
        matched: 'Obfuscated data URL detected',
        description: 'Data URL with obfuscated content',
        severity: 'medium',
        weight: 2,
        metadata: {
          technique: 'data-url-obfuscation'
        }
      }));
    }

    const matched = findings.length > 0;
    const riskScore = findings.reduce((sum, f) => sum + (f.weight || 1), 0);

    return this.createResult(matched, findings, riskScore);
  }

  isSuspiciousBlob(blob, rules) {
    const suspiciousTypes = rules.suspiciousMimeTypes || [
      'application/octet-stream',
      'application/x-msdownload',
      'application/exe',
      'application/x-exe',
      'application/x-msdos-program',
      'application/vnd.microsoft.portable-executable'
    ];

    // Check MIME type
    if (suspiciousTypes.includes(blob.mimeType)) {
      return {
        suspicious: true,
        reason: `Suspicious MIME type: ${blob.mimeType}`,
        severity: 'critical',
        weight: 5
      };
    }

    // Check size (large blobs are more suspicious)
    if (blob.size > (rules.blobSizeThreshold || 1000000)) {
      return {
        suspicious: true,
        reason: `Large blob file: ${blob.size} bytes`,
        severity: 'high',
        weight: 3
      };
    }

    return { suspicious: false };
  }

  hasExecutableExtension(filename, rules) {
    if (!filename) return false;

    const executableExts = rules.executableExtensions || [
      '.exe',
      '.dll',
      '.msi',
      '.bat',
      '.cmd',
      '.ps1',
      '.vbs',
      '.js',
      '.jar',
      '.app',
      '.dmg',
      '.pkg',
      '.sh'
    ];

    const filenameLower = filename.toLowerCase();
    return executableExts.some(ext => filenameLower.endsWith(ext));
  }
}
