// Clickjacking Detector - Detects transparent iframe overlays
// Browser Techniques Line 32: Transparent iframe overlays
// Use opacity/position to place sensitive buttons under lure content

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

export class ClickjackingDetector extends BaseDetector {
  constructor(config = {}) {
    super({
      name: 'clickjacking',
      category: 'social-engineering',
      version: '1.0.0',
      description: 'Detects clickjacking attempts via transparent iframes and UI redressing',
      weight: 2,
      severity: 'medium',
      ...config
    });
  }

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

    // This detector requires DOM data from content script
    const dom = target.dom || {};
    const headers = target.headers || {};

    if (!dom.iframes && !dom.overlays && !headers) {
      return this.createResult(false, [], 0);
    }

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

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

    // 1. Detect transparent/low-opacity iframes
    if (dom.iframes && Array.isArray(dom.iframes)) {
      for (const iframe of dom.iframes) {
        const opacity = parseFloat(iframe.opacity || 1);
        const visibility = iframe.visibility;

        // Check for very low opacity (likely clickjacking)
        if (opacity < (rules.opacityThreshold || 0.1) && opacity > 0) {
          findings.push(this.createFinding({
            pattern: 'transparent-iframe',
            matched: iframe.src || 'unknown iframe',
            description: `Transparent iframe detected (opacity: ${opacity})`,
            severity: 'high',
            weight: 4,
            metadata: {
              opacity,
              src: iframe.src,
              position: iframe.position,
              zIndex: iframe.zIndex,
              technique: 'transparent-overlay'
            }
          }));
        }

        // Check for hidden but interactive iframes
        if (visibility === 'hidden' && iframe.pointerEvents !== 'none') {
          findings.push(this.createFinding({
            pattern: 'hidden-interactive-iframe',
            matched: iframe.src || 'unknown iframe',
            description: 'Hidden iframe with interactive pointer events',
            severity: 'high',
            weight: 4,
            metadata: {
              visibility,
              pointerEvents: iframe.pointerEvents,
              technique: 'hidden-overlay'
            }
          }));
        }

        // Check for positioned overlays with high z-index
        if (
          (iframe.position === 'absolute' || iframe.position === 'fixed') &&
          iframe.zIndex > (rules.zIndexThreshold || 9999)
        ) {
          findings.push(this.createFinding({
            pattern: 'high-zindex-iframe',
            matched: iframe.src || 'unknown iframe',
            description: `Iframe with suspicious z-index (${iframe.zIndex})`,
            severity: 'medium',
            weight: 3,
            metadata: {
              zIndex: iframe.zIndex,
              position: iframe.position,
              technique: 'z-index-manipulation'
            }
          }));
        }
      }
    }

    // 2. Detect suspicious positioned overlays
    if (dom.overlays && Array.isArray(dom.overlays)) {
      for (const overlay of dom.overlays) {
        const opacity = parseFloat(overlay.opacity || 1);

        // Transparent overlay covering large area
        if (
          opacity < (rules.opacityThreshold || 0.1) &&
          overlay.coverage > 0.5 // Covers >50% of viewport
        ) {
          findings.push(this.createFinding({
            pattern: 'transparent-overlay',
            matched: `${overlay.tagName} element`,
            description: `Transparent overlay covering ${Math.round(overlay.coverage * 100)}% of page`,
            severity: 'high',
            weight: 4,
            metadata: {
              opacity,
              coverage: overlay.coverage,
              zIndex: overlay.zIndex,
              technique: 'ui-redressing'
            }
          }));
        }

        // Pointer-events manipulation
        if (overlay.pointerEvents === 'none' && overlay.hasChildWithPointerEvents) {
          findings.push(this.createFinding({
            pattern: 'pointer-events-bypass',
            matched: `${overlay.tagName} element`,
            description: 'Pointer-events manipulation to bypass click detection',
            severity: 'medium',
            weight: 3,
            metadata: {
              pointerEvents: overlay.pointerEvents,
              technique: 'pointer-events-abuse'
            }
          }));
        }
      }
    }

    // 3. Check for X-Frame-Options / CSP violations
    if (target.isFramed) {
      const xFrameOptions = headers['x-frame-options'];
      const csp = headers['content-security-policy'];

      // Page is framed but has no frame protection
      if (!xFrameOptions && !csp) {
        findings.push(this.createFinding({
          pattern: 'missing-frame-protection',
          matched: 'Page loaded in iframe without protection',
          description: 'No X-Frame-Options or CSP frame-ancestors header',
          severity: 'low',
          weight: 1,
          metadata: {
            isFramed: true,
            technique: 'missing-clickjacking-defense'
          }
        }));
      }

      // Check if framing violates X-Frame-Options
      if (xFrameOptions && xFrameOptions.toLowerCase() === 'deny') {
        findings.push(this.createFinding({
          pattern: 'frame-options-violation',
          matched: 'Page framed despite X-Frame-Options: DENY',
          description: 'Potential X-Frame-Options bypass attempt',
          severity: 'medium',
          weight: 2,
          metadata: {
            xFrameOptions,
            technique: 'header-bypass'
          }
        }));
      }
    }

    // 4. Detect multiple stacked iframes (iframe inception)
    if (dom.iframeDepth && dom.iframeDepth > 2) {
      findings.push(this.createFinding({
        pattern: 'iframe-inception',
        matched: `${dom.iframeDepth} levels of nested iframes`,
        description: 'Deeply nested iframes detected',
        severity: 'medium',
        weight: 2,
        metadata: {
          depth: dom.iframeDepth,
          technique: 'nested-frames'
        }
      }));
    }

    // 5. Detect suspicious CSS cursor manipulation
    if (dom.cursorMismatch) {
      findings.push(this.createFinding({
        pattern: 'cursor-manipulation',
        matched: 'Cursor style manipulation detected',
        description: 'Element cursor does not match underlying action',
        severity: 'low',
        weight: 1,
        metadata: {
          technique: 'cursor-spoofing'
        }
      }));
    }

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

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