// MIME Type Analysis Detector - Analyzes MIME types for malicious content

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

export class MimeTypeAnalysisDetector extends BaseDetector {
  constructor(config = {}) {
    super({
      name: 'mime-type-analysis',
      category: 'resource',
      version: '1.0.0',
      description: 'Detects suspicious MIME types in resources',
      weight: 2,
      severity: 'high',
      ...config
    });
  }

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

    const url = target.url;
    const mimeType = target.mimeType || target.contentType;
    const extension = target.extension || this.extractExtension(url);

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

    const rules = ruleRegistry.getRules('resource', 'mime-type');

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

    // 1. Check for executable MIME types
    if (this.isExecutableMimeType(mimeType, rules)) {
      findings.push(this.createFinding({
        pattern: 'executable-mime-type',
        matched: mimeType,
        description: `Executable MIME type detected: ${mimeType}`,
        severity: 'critical',
        weight: 5,
        metadata: {
          url,
          mimeType,
          extension,
          technique: 'executable-download'
        }
      }));
    }

    // 2. Detect MIME type / extension mismatches
    const mismatch = this.detectMimeExtensionMismatch(mimeType, extension, rules);
    if (mismatch) {
      findings.push(this.createFinding({
        pattern: 'mime-extension-mismatch',
        matched: `${extension} with ${mimeType}`,
        description: `MIME type doesn't match file extension: ${extension} vs ${mimeType}`,
        severity: 'high',
        weight: 4,
        metadata: {
          url,
          mimeType,
          extension,
          expectedMimeType: mismatch.expectedMimeType,
          technique: 'mime-spoofing'
        }
      }));
    }

    // 3. Flag suspicious content types
    const suspiciousMime = this.isSuspiciousMimeType(mimeType, rules);
    if (suspiciousMime) {
      findings.push(this.createFinding({
        pattern: 'suspicious-mime-type',
        matched: mimeType,
        description: `Suspicious MIME type: ${mimeType}`,
        severity: 'medium',
        weight: 3,
        metadata: {
          url,
          mimeType,
          reason: suspiciousMime.reason,
          technique: 'suspicious-content-type'
        }
      }));
    }

    // 4. Detect application/octet-stream abuse
    if (mimeType === 'application/octet-stream' && extension) {
      // octet-stream is often used to hide real file type
      findings.push(this.createFinding({
        pattern: 'generic-mime-type',
        matched: `${extension} as octet-stream`,
        description: 'Generic MIME type used (possible type hiding)',
        severity: 'medium',
        weight: 2,
        metadata: {
          url,
          mimeType,
          extension,
          technique: 'mime-obfuscation'
        }
      }));
    }

    // 5. Detect polyglot file indicators
    if (target.hasMultipleSignatures) {
      findings.push(this.createFinding({
        pattern: 'polyglot-file',
        matched: 'Multiple file signatures detected',
        description: 'File contains multiple format signatures (polyglot file)',
        severity: 'high',
        weight: 4,
        metadata: {
          url,
          mimeType,
          technique: 'polyglot-attack'
        }
      }));
    }

    // 6. Detect text/plain for binary content
    if (mimeType === 'text/plain' && target.size > 100000) {
      findings.push(this.createFinding({
        pattern: 'large-text-file',
        matched: `${target.size} bytes as text/plain`,
        description: 'Unusually large file served as text/plain',
        severity: 'low',
        weight: 1,
        metadata: {
          url,
          size: target.size,
          technique: 'mime-mislabeling'
        }
      }));
    }

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

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

  extractExtension(url) {
    try {
      const pathname = new URL(url).pathname;
      const match = pathname.match(/\.([a-z0-9]+)$/i);
      return match ? `.${match[1].toLowerCase()}` : null;
    } catch {
      return null;
    }
  }

  isExecutableMimeType(mimeType, rules) {
    const executableMimes = rules.executableMimeTypes || [
      'application/x-msdownload',
      'application/exe',
      'application/x-exe',
      'application/x-msdos-program',
      'application/vnd.microsoft.portable-executable',
      'application/x-dosexec',
      'application/x-executable',
      'application/x-sharedlib',
      'application/x-ms-dos-executable'
    ];

    return executableMimes.includes(mimeType);
  }

  detectMimeExtensionMismatch(mimeType, extension, rules) {
    if (!extension) return null;

    const expectedMimes = rules.extensionMimeMap || {
      '.pdf': 'application/pdf',
      '.jpg': 'image/jpeg',
      '.jpeg': 'image/jpeg',
      '.png': 'image/png',
      '.gif': 'image/gif',
      '.html': 'text/html',
      '.js': 'text/javascript',
      '.css': 'text/css',
      '.json': 'application/json',
      '.xml': 'text/xml',
      '.zip': 'application/zip',
      '.txt': 'text/plain'
    };

    const expectedMimeType = expectedMimes[extension.toLowerCase()];

    if (expectedMimeType && mimeType !== expectedMimeType) {
      return { expectedMimeType };
    }

    return null;
  }

  isSuspiciousMimeType(mimeType, rules) {
    const suspiciousMimes = rules.suspiciousMimeTypes || [
      'application/x-sh',
      'application/x-csh',
      'text/x-shellscript',
      'application/x-bat',
      'application/x-javascript',
      'text/vbscript'
    ];

    if (suspiciousMimes.includes(mimeType)) {
      return { reason: 'Script or executable content type' };
    }

    return null;
  }
}
