// Keyboard Instruction Detector
// Detects social engineering attacks instructing users to press keyboard shortcuts
// to run malicious commands (Win+R, Ctrl+R, etc.)
// Often used in phishing campaigns to bypass browser security

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

export class KeyboardInstruction extends BaseDetector {
  constructor(config = {}) {
    super(config);
  }

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

    if (!content || typeof content !== 'string') {
      return { detector: 'keyboard-instruction', matched: false, findings: [], riskScore: 0 };
    }

    // Normalize text for analysis (lowercase, remove extra whitespace)
    const normalizedText = content.toLowerCase().replace(/\s+/g, ' ');

    // Check for keyboard shortcut instructions
    const shortcutInstructions = this.detectShortcutInstructions(normalizedText);
    if (shortcutInstructions.matched) {
      findings.push({
        detector: 'keyboard-instruction',
        type: 'keyboard-shortcut-instruction',
        description: `Instructions to press ${shortcutInstructions.shortcuts.join(', ')} detected`,
        severity: shortcutInstructions.severity,
        weight: shortcutInstructions.weight,
        evidence: shortcutInstructions,
        mitre: ['T1204.002', 'T1566.002'] // User execution: malicious file, phishing link
      });
    }

    // Check for command execution instructions
    const commandInstructions = this.detectCommandInstructions(normalizedText);
    if (commandInstructions.matched) {
      findings.push({
        detector: 'keyboard-instruction',
        type: 'command-execution-instruction',
        description: `Instructions to run commands detected: ${commandInstructions.commands.join(', ')}`,
        severity: 'critical',
        weight: 5,
        evidence: commandInstructions,
        mitre: ['T1204.002', 'T1059.001', 'T1059.003'] // User execution, PowerShell, CMD
      });
    }

    // Check for paste-and-run instructions
    const pasteInstructions = this.detectPasteInstructions(normalizedText);
    if (pasteInstructions.matched) {
      findings.push({
        detector: 'keyboard-instruction',
        type: 'paste-and-run-instruction',
        description: 'Instructions to paste and run code detected',
        severity: 'critical',
        weight: 5,
        evidence: pasteInstructions,
        mitre: ['T1204.002', 'T1566.001'] // User execution, phishing
      });
    }

    // Check for urgency tactics (social engineering pressure)
    const urgencyTactics = this.detectUrgencyTactics(normalizedText);
    if (urgencyTactics.matched && findings.length > 0) {
      // Increase severity if urgency is combined with instructions
      findings[0].weight = Math.min(findings[0].weight + 1, 5);
      findings[0].evidence.urgencyDetected = true;
      findings[0].evidence.urgencyPhrases = urgencyTactics.phrases;
    }

    // Check for visual obfuscation (zero-width characters, hidden text)
    const obfuscation = this.detectVisualObfuscation(content);
    if (obfuscation.matched) {
      findings.push({
        detector: 'keyboard-instruction',
        type: 'visual-obfuscation',
        description: 'Hidden or obfuscated text detected',
        severity: 'high',
        weight: 4,
        evidence: obfuscation,
        mitre: ['T1027'] // Obfuscated files or information
      });
    }

    return {
      detector: 'keyboard-instruction',
      matched: findings.length > 0,
      findings,
      riskScore: this.calculateRiskScore(findings)
    };
  }

  /**
   * Detect keyboard shortcut instructions
   */
  detectShortcutInstructions(text) {
    const shortcuts = [];
    let severity = 'medium';
    let weight = 2;

    // Critical shortcuts (allow command execution)
    const criticalShortcuts = [
      {
        patterns: [
          /(?:press|hit|type|click|push)\s+(?:the\s+)?(?:windows|win)\s*\+\s*r/i,
          /(?:press|hit|type|click|push)\s+(?:the\s+)?(?:windows|win)\s+key\s+and\s+r/i,
          /(?:windows|win)\s*\+\s*r\s+(?:key|shortcut|combination)/i,
          /open\s+(?:the\s+)?run\s+(?:dialog|window|box)/i,
          /(?:press|hit|type)\s+(?:windows|win)\s+(?:key\s+)?\+\s+(?:x|r)/i
        ],
        shortcut: 'Win+R',
        risk: 'critical'
      },
      {
        patterns: [
          /(?:press|hit|type)\s+(?:ctrl|control)\s*\+\s*shift\s*\+\s*esc/i,
          /open\s+task\s+manager/i
        ],
        shortcut: 'Ctrl+Shift+Esc',
        risk: 'medium' // Less dangerous, but still suspicious
      },
      {
        patterns: [
          /(?:press|hit|type)\s+(?:cmd|ctrl|control)\s*\+\s*r/i,
          /(?:cmd|ctrl|control)\s*\+\s*r\s+to\s+(?:reload|refresh)/i
        ],
        shortcut: 'Ctrl+R',
        risk: 'low' // Browser refresh, but could be social engineering
      },
      {
        patterns: [
          /(?:press|hit|type)\s+(?:cmd|ctrl|control)\s*\+\s*v/i,
          /paste\s+(?:the\s+)?(?:command|code|text)/i,
          /(?:cmd|ctrl|control)\s*\+\s*v\s+(?:to\s+)?paste/i
        ],
        shortcut: 'Ctrl+V',
        risk: 'high' // Paste command (often followed by Enter)
      },
      {
        patterns: [
          /(?:press|hit|type)\s+enter/i,
          /hit\s+(?:the\s+)?return\s+key/i,
          /press\s+enter\s+(?:to\s+)?(?:run|execute|continue)/i
        ],
        shortcut: 'Enter',
        risk: 'high' // Execute command
      },
      {
        patterns: [
          /(?:press|hit|type)\s+f11/i,
          /f11\s+(?:to\s+)?(?:fullscreen|full\s+screen)/i
        ],
        shortcut: 'F11',
        risk: 'medium' // Fullscreen (can hide browser UI)
      }
    ];

    for (const { patterns, shortcut, risk } of criticalShortcuts) {
      for (const pattern of patterns) {
        if (pattern.test(text)) {
          shortcuts.push(shortcut);

          if (risk === 'critical') {
            severity = 'critical';
            weight = 5;
          } else if (risk === 'high' && severity !== 'critical') {
            severity = 'high';
            weight = 4;
          } else if (risk === 'medium' && severity === 'medium') {
            weight = 3;
          }

          break; // Don't double-count same shortcut
        }
      }
    }

    // Look for combinations (e.g., "Press Win+R, paste this, press Enter")
    const hasPasteAndEnter = shortcuts.includes('Ctrl+V') && shortcuts.includes('Enter');
    const hasRunAndPaste = shortcuts.includes('Win+R') && (shortcuts.includes('Ctrl+V') || /paste/.test(text));

    if (hasRunAndPaste || hasPasteAndEnter) {
      severity = 'critical';
      weight = 5;
    }

    return {
      matched: shortcuts.length > 0,
      shortcuts: [...new Set(shortcuts)], // Unique shortcuts
      severity,
      weight,
      multiStepAttack: shortcuts.length >= 3 || hasPasteAndEnter || hasRunAndPaste
    };
  }

  /**
   * Detect instructions to run specific commands
   */
  detectCommandInstructions(text) {
    const commands = [];

    const commandPatterns = [
      {
        pattern: /(?:type|enter|run|execute|copy|paste)\s+(?:this\s+)?(?:command|code|script):?\s*(?:powershell|cmd|certutil|mshta|regsvr32)/i,
        command: 'PowerShell/CMD command',
        severity: 'critical'
      },
      {
        pattern: /(?:run|execute|open)\s+(?:the\s+)?(?:command\s+prompt|cmd|powershell|terminal)/i,
        command: 'Open command prompt',
        severity: 'high'
      },
      {
        pattern: /(?:type|paste|enter)\s+(?:this\s+)?in\s+(?:the\s+)?(?:run\s+(?:dialog|window|box)|command\s+prompt|terminal)/i,
        command: 'Type in Run dialog',
        severity: 'critical'
      },
      {
        pattern: /copy\s+and\s+paste\s+(?:this\s+)?(?:command|code|script)/i,
        command: 'Copy and paste command',
        severity: 'critical'
      },
      {
        pattern: /(?:download|save)\s+and\s+(?:run|execute|open)\s+(?:this\s+)?(?:file|program|script)/i,
        command: 'Download and run',
        severity: 'critical'
      }
    ];

    for (const { pattern, command, severity } of commandPatterns) {
      if (pattern.test(text)) {
        commands.push(command);
      }
    }

    return {
      matched: commands.length > 0,
      commands: [...new Set(commands)],
      severity: 'critical'
    };
  }

  /**
   * Detect paste-and-run instructions
   */
  detectPasteInstructions(text) {
    const patterns = [
      /paste\s+(?:the\s+)?(?:following|this|below)\s+(?:command|code|script|text)/i,
      /copy\s+(?:and\s+)?paste\s+(?:the\s+)?(?:following|this|below)/i,
      /paste\s+(?:it\s+)?(?:into|in)\s+(?:the\s+)?(?:run|command|terminal|powershell|cmd)/i,
      /(?:ctrl|cmd|control)\s*\+\s*(?:v|c)\s+(?:and|then)\s+(?:enter|return)/i,
      /paste\s+(?:and\s+)?(?:press\s+)?enter/i,
      /paste\s+(?:and\s+)?(?:hit\s+)?return/i
    ];

    const matched = patterns.some(p => p.test(text));

    // Check if there's actual command content nearby
    const hasCommandContent = /(?:powershell|cmd|certutil|mshta|curl|wget|invoke-webrequest)/i.test(text);

    return {
      matched: matched,
      severity: hasCommandContent ? 'critical' : 'high',
      hasCommandContent
    };
  }

  /**
   * Detect urgency/pressure tactics
   */
  detectUrgencyTactics(text) {
    const urgencyPhrases = [
      /urgent(?:ly)?|immediately|right\s+now|asap|quickly|hurry/i,
      /(?:your\s+)?account\s+(?:will\s+be\s+)?(?:suspended|locked|closed|terminated)/i,
      /within\s+\d+\s+(?:hours?|minutes?|days?)/i,
      /(?:act\s+)?(?:now|immediately|quickly)/i,
      /limited\s+time|time\s+(?:is\s+)?running\s+out/i,
      /verify\s+(?:your\s+)?(?:account|identity|information)\s+(?:now|immediately)/i,
      /(?:update|confirm)\s+(?:your\s+)?(?:payment|billing|card)/i,
      /security\s+(?:alert|warning|notice)/i,
      /unauthorized\s+(?:access|activity|login)/i,
      /click\s+(?:here|below|this)\s+(?:now|immediately)/i
    ];

    const detectedPhrases = [];
    for (const pattern of urgencyPhrases) {
      const matches = text.match(pattern);
      if (matches) {
        detectedPhrases.push(matches[0]);
      }
    }

    return {
      matched: detectedPhrases.length >= 2, // At least 2 urgency indicators
      phrases: detectedPhrases
    };
  }

  /**
   * Detect visual obfuscation techniques
   */
  detectVisualObfuscation(text) {
    const techniques = [];

    // Zero-width characters
    const zeroWidthChars = /[\u200B\u200C\u200D\uFEFF]/g;
    const zwcMatches = text.match(zeroWidthChars);
    if (zwcMatches && zwcMatches.length > 5) {
      techniques.push({
        type: 'Zero-width characters',
        count: zwcMatches.length
      });
    }

    // Right-to-left override (can reverse text display)
    const rtlOverride = /[\u202E]/g;
    if (rtlOverride.test(text)) {
      techniques.push({
        type: 'RTL Override (text reversal)',
        severity: 'high'
      });
    }

    // Homoglyph characters (look-alike characters)
    const homoglyphs = /[αаеорсухӀӏ]/; // Cyrillic lookalikes for Latin
    if (homoglyphs.test(text)) {
      techniques.push({
        type: 'Homoglyph characters',
        severity: 'medium'
      });
    }

    // Excessive whitespace obfuscation
    const excessiveSpaces = text.match(/\s{10,}/g);
    if (excessiveSpaces && excessiveSpaces.length > 3) {
      techniques.push({
        type: 'Excessive whitespace',
        count: excessiveSpaces.length
      });
    }

    return {
      matched: techniques.length > 0,
      techniques
    };
  }
}
