// Overlay Credential Detector - Detects fake re-auth prompts
// Browser Techniques Line 201: Re-auth prompt spoofing
// Overlays prompt re-entry of credentials mid-session

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

export class OverlayCredentialDetector extends BaseDetector {
  constructor(config = {}) {
    super({
      name: 'overlay-credential',
      category: 'data-theft',
      version: '1.0.0',
      description: 'Detects fake credential overlays and re-auth prompts',
      weight: 4,
      severity: 'critical',
      ...config
    });
  }

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

    // This detector requires DOM data from content script
    const modals = target.modals || [];
    const overlays = target.overlays || [];
    const passwordFields = target.passwordFields || [];
    const isAuthenticated = target.isAuthenticated;

    if (modals.length === 0 && overlays.length === 0) {
      return this.createResult(false, [], 0);
    }

    const rules = ruleRegistry.getRules('data-theft', 'overlay-credential');

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

    // 1. Detect modals with credential fields
    for (const modal of modals) {
      if (this.hasCredentialFields(modal, rules)) {
        const suspicionScore = this.calculateOverlaySuspicion(modal, rules);

        if (suspicionScore >= 3) {
          findings.push(this.createFinding({
            pattern: 'credential-modal',
            matched: modal.id || 'credential modal',
            description: 'Suspicious modal dialog requesting credentials',
            severity: 'critical',
            weight: 5,
            metadata: {
              modalId: modal.id,
              suspicionScore,
              hasPasswordField: modal.hasPasswordField,
              hasUsernameField: modal.hasUsernameField,
              technique: 'overlay-credential-modal'
            }
          }));
        }
      }
    }

    // 2. Detect high z-index overlays with login forms
    for (const overlay of overlays) {
      if (overlay.zIndex > (rules.suspiciousZIndexThreshold || 1000) &&
          this.hasCredentialFields(overlay, rules)) {
        findings.push(this.createFinding({
          pattern: 'high-zindex-credential-overlay',
          matched: `z-index: ${overlay.zIndex}`,
          description: 'High z-index overlay with credential fields (phishing overlay)',
          severity: 'critical',
          weight: 5,
          metadata: {
            zIndex: overlay.zIndex,
            overlayId: overlay.id,
            technique: 'overlay-credential-zindex'
          }
        }));
      }
    }

    // 3. Detect "session expired" fake prompts
    for (const modal of modals) {
      if (this.hasSessionExpiredText(modal, rules) && this.hasCredentialFields(modal, rules)) {
        findings.push(this.createFinding({
          pattern: 'fake-session-expired',
          matched: modal.text,
          description: 'Fake "session expired" prompt requesting re-authentication',
          severity: 'critical',
          weight: 5,
          metadata: {
            modalText: modal.text,
            modalId: modal.id,
            technique: 'overlay-credential-session-expired'
          }
        }));
      }
    }

    // 4. Detect unexpected login forms on authenticated pages
    if (isAuthenticated) {
      const unexpectedLoginForms = [...modals, ...overlays].filter(element =>
        this.hasCredentialFields(element, rules) &&
        !this.isLegitimateReAuthPrompt(element, rules)
      );

      if (unexpectedLoginForms.length > 0) {
        findings.push(this.createFinding({
          pattern: 'unexpected-login-on-auth-page',
          matched: `${unexpectedLoginForms.length} unexpected login forms`,
          description: 'Unexpected login form on authenticated page',
          severity: 'high',
          weight: 4,
          metadata: {
            count: unexpectedLoginForms.length,
            technique: 'overlay-credential-unexpected'
          }
        }));
      }
    }

    // 5. Detect 2FA/OTP harvesting overlays
    for (const modal of modals) {
      if (this.is2FAHarvestingModal(modal, rules)) {
        findings.push(this.createFinding({
          pattern: '2fa-harvesting-overlay',
          matched: modal.text || '2FA overlay',
          description: 'Suspicious overlay requesting 2FA/OTP codes',
          severity: 'critical',
          weight: 5,
          metadata: {
            modalText: modal.text,
            modalId: modal.id,
            hasOtpField: modal.hasOtpField,
            technique: 'overlay-credential-2fa'
          }
        }));
      }
    }

    // 6. Detect overlays with cross-origin form actions
    for (const overlay of overlays) {
      if (this.hasCredentialFields(overlay, rules) && overlay.formAction) {
        const isCrossOrigin = this.isCrossOriginFormAction(
          overlay.formAction,
          target.currentOrigin
        );

        if (isCrossOrigin) {
          findings.push(this.createFinding({
            pattern: 'cross-origin-credential-form',
            matched: overlay.formAction,
            description: 'Credential overlay submits to different origin (phishing)',
            severity: 'critical',
            weight: 5,
            metadata: {
              formAction: overlay.formAction,
              currentOrigin: target.currentOrigin,
              technique: 'overlay-credential-cross-origin'
            }
          }));
        }
      }
    }

    // 7. Detect credential fields appearing mid-session
    if (target.credentialFieldsAddedMidSession) {
      findings.push(this.createFinding({
        pattern: 'mid-session-credential-fields',
        matched: 'Credentials requested mid-session',
        description: 'Credential input fields injected after page load',
        severity: 'high',
        weight: 4,
        metadata: {
          technique: 'overlay-credential-injection'
        }
      }));
    }

    // 8. Detect full-page overlays masking content
    for (const overlay of overlays) {
      if (this.isFullPageOverlay(overlay) && this.hasCredentialFields(overlay, rules)) {
        findings.push(this.createFinding({
          pattern: 'fullpage-credential-overlay',
          matched: 'Full-page credential overlay',
          description: 'Full-page overlay requesting credentials (masks legitimate page)',
          severity: 'critical',
          weight: 5,
          metadata: {
            overlayId: overlay.id,
            technique: 'overlay-credential-fullpage'
          }
        }));
      }
    }

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

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

  hasCredentialFields(element, rules) {
    return element.hasPasswordField ||
           element.hasUsernameField ||
           element.hasOtpField ||
           element.hasEmailField;
  }

  calculateOverlaySuspicion(modal, rules) {
    let score = 0;

    // High z-index is suspicious
    if (modal.zIndex > 1000) score++;

    // Positioned over existing content
    if (modal.position === 'fixed' || modal.position === 'absolute') score++;

    // Has both username and password (full login form)
    if (modal.hasUsernameField && modal.hasPasswordField) score++;

    // Contains urgency language
    if (this.hasUrgencyLanguage(modal.text, rules)) score++;

    // Cross-origin form submission
    if (modal.formAction && modal.formAction.includes('http')) {
      score++;
    }

    return score;
  }

  hasSessionExpiredText(modal, rules) {
    if (!modal.text) return false;

    const sessionExpiredPatterns = rules.sessionExpiredPatterns || [
      'session expired',
      'session has expired',
      'logged out',
      'please log in again',
      'please sign in again',
      'authentication required',
      'verify your identity',
      'confirm your credentials'
    ];

    const textLower = modal.text.toLowerCase();
    return sessionExpiredPatterns.some(pattern => textLower.includes(pattern));
  }

  hasUrgencyLanguage(text, rules) {
    if (!text) return false;

    const urgencyPatterns = rules.urgencyPatterns || [
      'urgent',
      'immediate',
      'act now',
      'suspended',
      'locked',
      'unusual activity',
      'verify now',
      'confirm immediately'
    ];

    const textLower = text.toLowerCase();
    return urgencyPatterns.some(pattern => textLower.includes(pattern));
  }

  is2FAHarvestingModal(modal, rules) {
    if (!modal.text && !modal.hasOtpField) return false;

    const has2FAField = modal.hasOtpField ||
                        modal.hasTotpField ||
                        modal.hasVerificationCodeField;

    if (!has2FAField) return false;

    // Check for 2FA-related text
    const textLower = (modal.text || '').toLowerCase();
    const twoFAPatterns = rules.twoFAPatterns || [
      '2fa', 'two-factor', 'authentication code',
      'verification code', 'otp', 'one-time password',
      'enter the code', 'security code'
    ];

    const has2FAText = twoFAPatterns.some(pattern => textLower.includes(pattern));

    return has2FAField || has2FAText;
  }

  isLegitimateReAuthPrompt(element, rules) {
    // Legitimate re-auth prompts are rare and usually from the same origin
    // This is a placeholder - in practice, would check against known patterns
    return false;
  }

  isCrossOriginFormAction(formAction, currentOrigin) {
    if (!formAction || !currentOrigin) return false;

    try {
      const actionUrl = new URL(formAction, currentOrigin);
      const actionOrigin = actionUrl.origin;

      return actionOrigin !== currentOrigin;
    } catch {
      return false;
    }
  }

  isFullPageOverlay(overlay) {
    return overlay.width >= 90 && overlay.height >= 90; // 90% or more of viewport
  }
}
