// PhishProtect: Dynamic Script Tracker
// Runs in page context (main world). Hooks DOM insertion methods to log
// dynamically injected <script> elements before they can self-remove.
// Data stored in window.__phishprotect_dynamicScripts for evidence collection.

(function() {
  'use strict';

  const MAX_TRACKED = 20;
  const MAX_INLINE_CHARS = 2000;
  const tracked = [];

  // Expose for content-script / source-snippet-collector to read
  window.__phishprotect_dynamicScripts = tracked;

  function captureScript(scriptEl) {
    if (tracked.length >= MAX_TRACKED) return;
    try {
      // Skip our own extension scripts
      if (scriptEl.src && scriptEl.src.includes('chrome-extension://')) return;

      const entry = {
        timestamp: Date.now(),
        src: scriptEl.src || null,
        textContent: null,
        textLength: 0,
        insertionStack: null
      };

      // Inline script content
      if (!scriptEl.src) {
        const text = scriptEl.textContent || '';
        entry.textLength = text.length;
        entry.textContent = text.substring(0, MAX_INLINE_CHARS);
      }

      // Stack trace showing who inserted this script
      try {
        const stack = new Error().stack;
        entry.insertionStack = stack.split('\n')
          .filter(line => !line.includes('chrome-extension://'))
          .slice(2, 10) // skip captureScript + the hook frame
          .map(line => line.trim());
      } catch (e) {}

      // Avoid duplicates (same src or same text)
      const isDuplicate = tracked.some(t =>
        (entry.src && t.src === entry.src) ||
        (!entry.src && entry.textContent && t.textContent === entry.textContent)
      );
      if (!isDuplicate) {
        tracked.push(entry);
      }
    } catch (e) {}
  }

  // Hook appendChild
  const origAppendChild = Node.prototype.appendChild;
  Node.prototype.appendChild = function(child) {
    if (child && child.nodeName === 'SCRIPT') {
      // Defer to next microtask so textContent/src are fully set
      Promise.resolve().then(() => captureScript(child));
    }
    return origAppendChild.call(this, child);
  };

  // Hook insertBefore
  const origInsertBefore = Node.prototype.insertBefore;
  Node.prototype.insertBefore = function(child, ref) {
    if (child && child.nodeName === 'SCRIPT') {
      Promise.resolve().then(() => captureScript(child));
    }
    return origInsertBefore.call(this, child, ref);
  };

  // Hook append (modern API, takes multiple args)
  const origAppend = Element.prototype.append;
  if (origAppend) {
    Element.prototype.append = function(...args) {
      for (const arg of args) {
        if (arg && arg.nodeName === 'SCRIPT') {
          Promise.resolve().then(() => captureScript(arg));
        }
      }
      return origAppend.call(this, ...args);
    };
  }
})();
