// Dialog Trap Detector - Detects alert/prompt loops
// Browser Techniques Line 246: beforeunload loops
// Beforeunload handlers make closing difficult

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

export class DialogTrapDetector extends BaseDetector {
  constructor(config = {}) {
    super({
      name: 'dialog-trap',
      category: 'social-engineering',
      version: '1.0.0',
      description: 'Detects dialog and beforeunload traps that prevent navigation',
      weight: 2,
      severity: 'medium',
      ...config
    });
  }

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

    // This detector requires dialog event monitoring data
    const dialogEvents = target.dialogEvents || [];
    const hasBeforeUnload = target.hasBeforeUnload || false;
    const popupCount = target.popupCount || 0;
    const historyLoopDetected = target.historyLoopDetected || false;

    if (
      dialogEvents.length === 0 &&
      !hasBeforeUnload &&
      popupCount === 0 &&
      !historyLoopDetected
    ) {
      return this.createResult(false, [], 0);
    }

    const rules = ruleRegistry.getRules('social-engineering', 'dialog-trap');

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

    // 1. Detect rapid repeated dialogs
    if (dialogEvents.length > 0) {
      const rapidDialogs = this.detectRapidDialogs(
        dialogEvents,
        rules.rapidDialogThreshold || 3,
        rules.rapidDialogTimeWindow || 5000
      );

      if (rapidDialogs.count >= rules.rapidDialogThreshold) {
        findings.push(this.createFinding({
          pattern: 'rapid-dialog-loop',
          matched: `${rapidDialogs.count} dialogs in ${rapidDialogs.timeWindow}ms`,
          description: 'Rapid repeated dialog boxes detected (dialog trap)',
          severity: 'high',
          weight: 4,
          metadata: {
            dialogCount: rapidDialogs.count,
            timeWindow: rapidDialogs.timeWindow,
            dialogTypes: rapidDialogs.types,
            technique: 'dialog-flooding'
          }
        }));
      }
    }

    // 2. Detect beforeunload trap
    if (hasBeforeUnload) {
      const message = target.beforeUnloadMessage || '';
      const isSuspicious = this.isBeforeUnloadSuspicious(message, rules);

      if (isSuspicious) {
        findings.push(this.createFinding({
          pattern: 'beforeunload-trap',
          matched: message.substring(0, 50),
          description: 'Suspicious beforeunload handler preventing navigation',
          severity: 'medium',
          weight: 3,
          metadata: {
            message,
            technique: 'navigation-blocking'
          }
        }));
      }
    }

    // 3. Detect popup spam
    if (popupCount >= (rules.popupSpamThreshold || 3)) {
      findings.push(this.createFinding({
        pattern: 'popup-spam',
        matched: `${popupCount} popup windows`,
        description: 'Excessive popup window creation detected',
        severity: 'high',
        weight: 4,
        metadata: {
          popupCount,
          technique: 'popup-flooding'
        }
      }));
    }

    // 4. Detect history manipulation loop
    if (historyLoopDetected) {
      findings.push(this.createFinding({
        pattern: 'history-loop',
        matched: 'History manipulation loop detected',
        description: 'Page using history API to prevent back navigation',
        severity: 'medium',
        weight: 3,
        metadata: {
          technique: 'history-manipulation'
        }
      }));
    }

    // 5. Detect infinite loop dialogs
    const infiniteLoopDialogs = dialogEvents.filter(
      e => e.inInfiniteLoop || e.isRecursive
    );

    if (infiniteLoopDialogs.length > 0) {
      findings.push(this.createFinding({
        pattern: 'infinite-dialog-loop',
        matched: `${infiniteLoopDialogs.length} infinite loop dialogs`,
        description: 'Dialogs triggered from infinite loop (severe trap)',
        severity: 'critical',
        weight: 5,
        metadata: {
          count: infiniteLoopDialogs.length,
          technique: 'infinite-loop-trap'
        }
      }));
    }

    // 6. Detect scareware dialogs
    if (dialogEvents.length > 0) {
      const scarewareDialogs = dialogEvents.filter(e =>
        this.isScarewareMessage(e.message, rules)
      );

      if (scarewareDialogs.length > 0) {
        findings.push(this.createFinding({
          pattern: 'scareware-dialog',
          matched: `${scarewareDialogs.length} scareware messages`,
          description: 'Dialog boxes with scareware/intimidation content',
          severity: 'high',
          weight: 4,
          metadata: {
            count: scarewareDialogs.length,
            examples: scarewareDialogs.slice(0, 2).map(d => d.message),
            technique: 'scareware'
          }
        }));
      }
    }

    // 7. Detect auto-closing prevention
    if (target.preventsAutoClose) {
      findings.push(this.createFinding({
        pattern: 'prevent-auto-close',
        matched: 'Auto-close prevention detected',
        description: 'Page prevents automatic window/tab closing',
        severity: 'medium',
        weight: 2,
        metadata: {
          technique: 'close-prevention'
        }
      }));
    }

    // 8. Detect prompt fishing
    const promptDialogs = dialogEvents.filter(e => e.type === 'prompt');
    if (promptDialogs.length > 0) {
      const suspiciousPrompts = promptDialogs.filter(p =>
        this.isPromptFishing(p.message, rules)
      );

      if (suspiciousPrompts.length > 0) {
        findings.push(this.createFinding({
          pattern: 'prompt-fishing',
          matched: `${suspiciousPrompts.length} suspicious prompts`,
          description: 'Prompt dialogs requesting sensitive information',
          severity: 'high',
          weight: 4,
          metadata: {
            count: suspiciousPrompts.length,
            technique: 'credential-harvesting'
          }
        }));
      }
    }

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

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

  detectRapidDialogs(dialogEvents, threshold, timeWindow) {
    if (dialogEvents.length < threshold) {
      return { count: 0, timeWindow: 0, types: [] };
    }

    // Sort by timestamp
    const sorted = [...dialogEvents].sort((a, b) => a.timestamp - b.timestamp);

    // Check sliding window
    for (let i = 0; i <= sorted.length - threshold; i++) {
      const window = sorted.slice(i, i + threshold);
      const windowTime = window[window.length - 1].timestamp - window[0].timestamp;

      if (windowTime <= timeWindow) {
        return {
          count: threshold,
          timeWindow: windowTime,
          types: window.map(d => d.type)
        };
      }
    }

    return { count: 0, timeWindow: 0, types: [] };
  }

  isBeforeUnloadSuspicious(message, rules) {
    if (!message) return true; // Empty message but handler exists

    const suspiciousPatterns = rules.beforeUnloadPatterns || [
      'leave',
      'sure',
      'stay',
      'changes',
      'unsaved',
      'lose',
      'discard'
    ];

    const messageLower = message.toLowerCase();

    // Generic patterns are less suspicious than specific scareware
    const hasGenericPattern = suspiciousPatterns.some(pattern =>
      messageLower.includes(pattern)
    );

    // More suspicious if it's a long threatening message
    return !hasGenericPattern || message.length > 100;
  }

  isScarewareMessage(message, rules) {
    if (!message) return false;

    const scarewarePatterns = rules.scarewarePatterns || [
      'virus',
      'infected',
      'hacked',
      'compromised',
      'warning',
      'alert',
      'critical',
      'urgent',
      'security threat',
      'malware',
      'trojan',
      'call.*support',
      'call.*now',
      'toll.*free',
      'click.*here.*fix',
      'system.*error',
      'windows.*defender',
      'microsoft.*support'
    ];

    const messageLower = message.toLowerCase();

    return scarewarePatterns.some(pattern => {
      const regex = new RegExp(pattern, 'i');
      return regex.test(messageLower);
    });
  }

  isPromptFishing(message, rules) {
    if (!message) return false;

    const fishingPatterns = rules.promptFishingPatterns || [
      'password',
      'credit card',
      'social security',
      'ssn',
      'account number',
      'pin',
      'verification code',
      'confirm your',
      'enter your'
    ];

    const messageLower = message.toLowerCase();

    return fishingPatterns.some(pattern => messageLower.includes(pattern));
  }
}
