// Dialog Trap Signal Providers
// Extracts typed features from dialog events, beforeunload state, and popup behavior.
// Each provider returns { value, metadata? } — no decisions, no severity, no findings.

// ── Scareware patterns ──────────────────────────
const SCAREWARE_PATTERNS = [
  /virus/i, /infected/i, /hacked/i, /compromised/i,
  /malware/i, /trojan/i, /security threat/i,
  /call.*support/i, /call.*now/i, /toll.*free/i,
  /click.*here.*fix/i, /system.*error/i,
  /windows.*defender/i, /microsoft.*support/i,
];

// ── Generic beforeunload patterns (benign) ──────
const GENERIC_BEFOREUNLOAD = [
  'leave', 'sure', 'stay', 'changes', 'unsaved', 'lose', 'discard',
];

// ── Prompt fishing patterns ─────────────────────
const PROMPT_FISHING_PATTERNS = [
  'password', 'credit card', 'social security', 'ssn',
  'account number', 'pin', 'verification code',
  'confirm your', 'enter your',
];

/**
 * Register all dialog-trap signal providers on a SignalProviderRegistry.
 * @param {import('../../core/signal-provider.js').SignalProviderRegistry} registry
 */
export function registerDialogTrapSignals(registry) {

  // ── dialog.rapid_count ────────────────────────
  registry.register('dialog', 'rapid_count', (target) => {
    const events = target.dialogEvents || [];
    if (events.length < 2) return { value: 0 };

    const timeWindow = 5000;
    const threshold = 3;
    const sorted = [...events].sort((a, b) => a.timestamp - b.timestamp);

    let maxInWindow = 0;
    let windowTypes = [];
    for (let i = 0; i <= sorted.length - threshold; i++) {
      const window = sorted.slice(i, i + threshold);
      const dt = window[window.length - 1].timestamp - window[0].timestamp;
      if (dt <= timeWindow && threshold > maxInWindow) {
        maxInWindow = threshold;
        windowTypes = window.map(d => d.type);
      }
    }

    // Also check if total count exceeds threshold even without tight window
    const totalCount = events.length;
    const effectiveCount = Math.max(maxInWindow, totalCount >= threshold ? totalCount : 0);

    return {
      value: effectiveCount,
      metadata: effectiveCount > 0 ? { dialogTypes: windowTypes, totalDialogs: totalCount } : null,
    };
  }, { returnType: 'number', scope: 'tab', description: 'Count of rapid dialogs in time window' });

  // ── dialog.has_infinite_loop ──────────────────
  registry.register('dialog', 'has_infinite_loop', (target) => {
    const events = target.dialogEvents || [];
    const loopDialogs = events.filter(e => e.inInfiniteLoop || e.isRecursive);
    return {
      value: loopDialogs.length > 0,
      metadata: loopDialogs.length > 0 ? { count: loopDialogs.length } : null,
    };
  }, { returnType: 'boolean', scope: 'tab', description: 'Infinite loop dialogs detected' });

  // ── dialog.scareware_count ────────────────────
  registry.register('dialog', 'scareware_count', (target) => {
    const events = target.dialogEvents || [];
    if (events.length === 0) return { value: 0 };

    const scarewareDialogs = events.filter(e => {
      if (!e.message) return false;
      return SCAREWARE_PATTERNS.some(p => p.test(e.message));
    });

    return {
      value: scarewareDialogs.length,
      metadata: scarewareDialogs.length > 0 ? {
        examples: scarewareDialogs.slice(0, 2).map(d => d.message?.substring(0, 80)),
      } : null,
    };
  }, { returnType: 'number', scope: 'tab', description: 'Count of dialog boxes with scareware content' });

  // ── dialog.prompt_fishing_count ───────────────
  registry.register('dialog', 'prompt_fishing_count', (target) => {
    const events = target.dialogEvents || [];
    const prompts = events.filter(e => e.type === 'prompt');
    if (prompts.length === 0) return { value: 0 };

    const suspicious = prompts.filter(p => {
      if (!p.message) return false;
      const msg = p.message.toLowerCase();
      return PROMPT_FISHING_PATTERNS.some(pat => msg.includes(pat));
    });

    return {
      value: suspicious.length,
      metadata: suspicious.length > 0 ? { prompts: suspicious.length } : null,
    };
  }, { returnType: 'number', scope: 'tab', description: 'Count of prompts asking for sensitive info' });

  // ── page.has_beforeunload_trap ────────────────
  registry.register('page', 'has_beforeunload_trap', (target) => {
    if (!target.hasBeforeUnload) return { value: false };

    const message = target.beforeUnloadMessage || '';
    // Empty message but handler exists → suspicious
    if (!message) return { value: true, metadata: { reason: 'empty-message' } };

    const msgLower = message.toLowerCase();
    const hasGeneric = GENERIC_BEFOREUNLOAD.some(p => msgLower.includes(p));

    // Suspicious if NOT generic, or if generic but very long (scareware-like)
    const isSuspicious = !hasGeneric || message.length > 100;
    return {
      value: isSuspicious,
      metadata: isSuspicious ? { messageLength: message.length, hasGeneric } : null,
    };
  }, { returnType: 'boolean', scope: 'tab', description: 'Suspicious beforeunload handler preventing navigation' });

  // ── page.popup_count ──────────────────────────
  registry.register('page', 'popup_count', (target) => {
    const count = target.popupCount || 0;
    return { value: count };
  }, { returnType: 'number', scope: 'tab', description: 'Number of popup windows created' });

  // ── page.has_history_loop ─────────────────────
  registry.register('page', 'has_history_loop', (target) => {
    return { value: !!target.historyLoopDetected };
  }, { returnType: 'boolean', scope: 'tab', description: 'History API manipulation loop detected' });

  // ── page.prevents_auto_close ──────────────────
  registry.register('page', 'prevents_auto_close', (target) => {
    return { value: !!target.preventsAutoClose };
  }, { returnType: 'boolean', scope: 'tab', description: 'Page prevents automatic window/tab closing' });
}
