// ImposterShield content script (v0.2).
// Collects the biggest images on the page plus page-level signals and hands
// them to the service worker, which does the byte-level checking and (when a
// classifier key is configured) the looks-like-AI scoring.
//
// v0.2 fixes the v0.1 timing bug: scanning only at document_idle missed
// images that hadn't finished loading, so pages could stay green. Now we
// rescan on window load, when late images finish, and on DOM changes.

(function () {
  var MAX_IMAGES = 24;
  var MIN_DIM = 100;
  var MAX_BG_ELEMENTS = 3000;
  var MAX_SCANS = 6;
  var scanCount = 0;
  var lastScanAt = 0;
  var pendingScan = null;

  function bgUrl(el) {
    var bg = getComputedStyle(el).backgroundImage;
    if (!bg || bg === 'none' || bg.indexOf('url(') === -1) return null;
    var m = bg.match(/url\((['"]?)(.*?)\1\)/);
    return m ? m[2] : null;
  }

  function collectImages() {
    var seen = {};
    var out = [];
    var imgs = document.images;
    for (var i = 0; i < imgs.length; i++) {
      var img = imgs[i];
      if (img.naturalWidth < MIN_DIM || img.naturalHeight < MIN_DIM) continue;
      var url = img.currentSrc || img.src;
      if (!url || seen[url]) continue;
      if (url.indexOf('http') !== 0 && url.indexOf('data:') !== 0) continue;
      seen[url] = true;
      out.push({
        url: url,
        w: img.naturalWidth,
        h: img.naturalHeight,
        area: img.naturalWidth * img.naturalHeight,
        alt: (img.alt || '').slice(0, 200)
      });
    }
    // CSS background images: icons and hero art often live here, not in <img>.
    var els = document.querySelectorAll('div,span,section,a,li,figure,header,i,b');
    for (var j = 0; j < els.length && j < MAX_BG_ELEMENTS; j++) {
      var el = els[j];
      if (el.offsetWidth < MIN_DIM || el.offsetHeight < MIN_DIM) continue;
      var u = bgUrl(el);
      if (!u || seen[u]) continue;
      if (u.indexOf('http') !== 0 && u.indexOf('data:') !== 0) continue;
      seen[u] = true;
      out.push({ url: u, w: el.offsetWidth, h: el.offsetHeight, area: el.offsetWidth * el.offsetHeight, alt: '' });
    }
    out.sort(function (a, b) { return b.area - a.area; });
    return out.slice(0, MAX_IMAGES);
  }

  function pageSignals() {
    var gen = document.querySelector('meta[name="generator"]');
    return {
      generator: gen ? (gen.getAttribute('content') || '') : '',
      title: (document.title || '').slice(0, 200)
    };
  }

  function runScan(force) {
    if (scanCount >= MAX_SCANS && !force) return;
    var now = Date.now();
    // Coalesce bursts (mutation storms, many image load events) into one scan.
    if (now - lastScanAt < 3000 && !force) {
      if (!pendingScan) {
        pendingScan = setTimeout(function () { pendingScan = null; runScan(); }, 3200 - (now - lastScanAt));
      }
      return;
    }
    lastScanAt = now;
    scanCount++;
    try {
      chrome.runtime.sendMessage({
        type: 'IS_SCAN',
        images: collectImages(),
        signals: pageSignals()
      });
    } catch (e) { /* extension reloaded mid-page; nothing to do */ }
  }

  function outline(img, color, style, title) {
    img.style.outline = '3px ' + style + ' ' + color;
    img.style.outlineOffset = '-3px';
    img.setAttribute('data-impostershield', style === 'solid' ? 'flagged' : 'likely');
    img.title = title;
  }

  function markResults(msg) {
    var proven = msg.proven || [];
    var likely = msg.likely || [];
    var imgs = document.images;
    for (var i = 0; i < imgs.length; i++) {
      var img = imgs[i];
      var url = img.currentSrc || img.src;
      if (proven.indexOf(url) !== -1) {
        outline(img, msg.color || '#FFB020', 'solid', 'ImposterShield: this image carries AI-generation markers.');
      } else if (likely.indexOf(url) !== -1) {
        outline(img, '#FF8C42', 'dashed', 'ImposterShield: an image classifier rates this as likely AI-made. Not proof.');
      }
    }
    // Outline elements whose flagged image arrived via CSS background.
    var els = document.querySelectorAll('div,span,section,a,li,figure,header,i,b');
    for (var j = 0; j < els.length && j < MAX_BG_ELEMENTS; j++) {
      var el = els[j];
      if (el.offsetWidth < MIN_DIM || el.offsetHeight < MIN_DIM) continue;
      var u = bgUrl(el);
      if (!u) continue;
      if (proven.indexOf(u) !== -1) {
        outline(el, msg.color || '#FFB020', 'solid', 'ImposterShield: this image carries AI-generation markers.');
      } else if (likely.indexOf(u) !== -1) {
        outline(el, '#FF8C42', 'dashed', 'ImposterShield: an image classifier rates this as likely AI-made. Not proof.');
      }
    }
  }

  chrome.runtime.onMessage.addListener(function (msg) {
    if (msg && msg.type === 'IS_MARK') markResults(msg);
    if (msg && msg.type === 'IS_RESCAN') runScan(true);
  });

  // Scan triggers: idle (now), full load, late-loading images, DOM changes.
  runScan();
  if (document.readyState !== 'complete') {
    window.addEventListener('load', function () { setTimeout(runScan, 400); });
  }
  document.addEventListener('load', function (e) {
    if (e.target && e.target.tagName === 'IMG') runScan();
  }, true);
  var mo = new MutationObserver(function (muts) {
    for (var i = 0; i < muts.length; i++) {
      var m = muts[i];
      if (m.addedNodes && m.addedNodes.length) { runScan(); return; }
    }
  });
  mo.observe(document.documentElement, { childList: true, subtree: true });
  setTimeout(function () { mo.disconnect(); }, 30000);
})();
