(() => {
  const SCRAPE_DEBOUNCE_MS = 600;
  let scrapeTimer = null;
  let lastSerialized = "";

  // Selectors are intentionally broad: casino.org uses a mix of editorial
  // listings, comparison tables and review cards, so we union several common
  // patterns and let the popup display whatever was found.
  const ITEM_SELECTORS = [
    '[data-testid*="casino" i]',
    '[data-test*="casino" i]',
    'article[class*="casino" i]',
    'article[class*="review" i]',
    'div[class*="casino-card" i]',
    'div[class*="casino-listing" i]',
    'li[class*="casino" i]',
    'tr[class*="casino" i]'
  ].join(",");

  function pickText(root, selectors) {
    for (const sel of selectors) {
      const el = root.querySelector(sel);
      const txt = el?.innerText?.trim();
      if (txt) return txt;
    }
    return null;
  }

  function extractRow(el) {
    const name = pickText(el, [
      '[data-testid*="name" i]',
      'h2', 'h3', 'h4',
      '.title', '[class*="title" i]',
      '[class*="name" i]'
    ]);
    const rating = pickText(el, [
      '[data-testid*="rating" i]',
      '[class*="rating" i]',
      '[class*="score" i]',
      '[itemprop="ratingValue"]'
    ]);
    const bonus = pickText(el, [
      '[data-testid*="bonus" i]',
      '[class*="bonus" i]',
      '[class*="offer" i]',
      '[class*="promo" i]'
    ]);
    const link = el.querySelector('a[href]');
    const url = link ? link.href : null;
    if (!name && !bonus && !rating) return null;
    return { name, rating, bonus, url };
  }

  function scrape() {
    const els = document.querySelectorAll(ITEM_SELECTORS);
    const rows = [];
    const seen = new Set();
    els.forEach((el) => {
      const row = extractRow(el);
      if (!row) return;
      const key = `${row.name}|${row.url}`;
      if (seen.has(key)) return;
      seen.add(key);
      rows.push(row);
    });

    const payload = {
      kind: "pageData",
      url: location.href,
      title: document.title,
      rows
    };
    const serialized = JSON.stringify(payload.rows);
    if (serialized === lastSerialized) return;
    lastSerialized = serialized;

    try {
      chrome.runtime.sendMessage(payload, () => void chrome.runtime.lastError);
    } catch (_) {
      // Extension context may be invalidated on reload; ignore.
    }
  }

  function scheduleScrape() {
    if (scrapeTimer) clearTimeout(scrapeTimer);
    scrapeTimer = setTimeout(scrape, SCRAPE_DEBOUNCE_MS);
  }

  scheduleScrape();

  const mo = new MutationObserver(scheduleScrape);
  mo.observe(document.documentElement, {
    childList: true,
    subtree: true,
    characterData: false
  });

  // Catch SPA route changes that don't trigger DOM mutations immediately.
  const wrap = (name) => {
    const orig = history[name];
    history[name] = function (...args) {
      const ret = orig.apply(this, args);
      window.dispatchEvent(new Event("casino-org-locationchange"));
      return ret;
    };
  };
  wrap("pushState");
  wrap("replaceState");
  window.addEventListener("popstate", () => window.dispatchEvent(new Event("casino-org-locationchange")));
  window.addEventListener("casino-org-locationchange", scheduleScrape);
})();
