"use client";

import { useEffect } from "react";

/**
 * Canonical RMP banner tracking + dedup component.
 *
 * Synced from advertising-rmp/src/lib/canonical/BannerTracking.tsx.
 * Do NOT edit per-property copies — update the canonical file in the
 * advertising-rmp repo and re-sync. The RMP banner-tracking standard
 * (docs: infra-docs/rmp-banner-tracking-standard.md) requires this
 * exact behavior on every property — gross-impression-on-mount
 * (AdSanity-style), plus viewport dedup of duplicate creatives.
 */

interface Props {
  property: string;
}

const ENDPOINT = "https://advertising.relevantmediaproperties.com/api/track/impression";

const SELECTOR =
  '[data-campaign-id], [data-ad-slug], [data-ad-zone], [data-banner], .ad-unit, [class*="AdImage"], [class*="AdSlot"], [class*="AdBanner"], [class*="BannerAd"]';

export default function BannerTracking({ property }: Props) {
  useEffect(() => {
    if (typeof window === "undefined") return;

    let sid = sessionStorage.getItem("rmp.session");
    if (!sid) {
      sid =
        typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
          ? crypto.randomUUID()
          : Math.random().toString(36).slice(2) + Date.now().toString(36);
      sessionStorage.setItem("rmp.session", sid);
    }

    const fired = new WeakSet<Element>();
    const visibleByKey = new Map<string, Element>();
    const hiddenByUs = new WeakSet<Element>();

    function isNested(el: Element): boolean {
      return !!el.parentElement?.closest(SELECTOR);
    }

    function fireBeacon(el: Element): void {
      if (fired.has(el)) return;
      if (isNested(el)) return;
      fired.add(el);

      const campaign_id = el.getAttribute("data-campaign-id") || undefined;
      const slug = el.getAttribute("data-ad-slug") || undefined;
      if (!campaign_id && !slug) return;

      const payload = JSON.stringify({
        campaign_id,
        slug,
        property,
        page_path: location.pathname,
        page_url: location.href,
        session_id: sid,
        viewport: false,
      });

      try {
        if (typeof navigator.sendBeacon === "function") {
          navigator.sendBeacon(
            ENDPOINT,
            new Blob([payload], { type: "application/json" })
          );
        } else {
          void fetch(ENDPOINT, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: payload,
            keepalive: true,
          }).catch(() => {});
        }
      } catch {
        // never throw to the page
      }
    }

    function keyOf(el: Element): string | null {
      const cid = el.getAttribute("data-campaign-id");
      if (cid) return `c:${cid}`;

      const anchor =
        el.matches("a[href]")
          ? el
          : el.querySelector("a[href]") ?? el.closest("a[href]");
      const href = anchor?.getAttribute("href");
      if (href && !href.startsWith("#")) return `h:${href}`;

      const img = el.querySelector("img[src]") as HTMLImageElement | null;
      const src = img?.getAttribute("src");
      if (src) return `i:${src}`;

      return null;
    }

    const io = new IntersectionObserver(
      (entries) => {
        for (const e of entries) {
          const el = e.target;
          const key = keyOf(el);
          if (!key) continue;

          if (e.isIntersecting) {
            const cur = visibleByKey.get(key);
            if (cur && cur !== el) {
              (el as HTMLElement).style.setProperty("display", "none", "important");
              el.setAttribute("data-deduped", "auto");
              hiddenByUs.add(el);
            } else {
              visibleByKey.set(key, el);
            }
          } else {
            if (hiddenByUs.has(el)) continue;
            if (visibleByKey.get(key) === el) {
              visibleByKey.delete(key);
              const candidates = Array.from(
                document.querySelectorAll(SELECTOR)
              ).filter(
                (c) =>
                  !isNested(c) && keyOf(c) === key && hiddenByUs.has(c)
              );
              if (candidates.length > 0) {
                const c = candidates[0] as HTMLElement;
                c.style.removeProperty("display");
                c.removeAttribute("data-deduped");
                hiddenByUs.delete(c);
              }
            }
          }
        }
      },
      { threshold: 0.3 }
    );

    function register(el: Element): void {
      if (isNested(el)) return;
      fireBeacon(el);
      io.observe(el);
    }

    document.querySelectorAll(SELECTOR).forEach(register);

    const mo = new MutationObserver((muts) => {
      for (const m of muts) {
        m.addedNodes.forEach((n) => {
          if (n.nodeType !== 1) return;
          const el = n as Element;
          if (el.matches?.(SELECTOR)) register(el);
          el.querySelectorAll?.(SELECTOR).forEach(register);
        });
      }
    });
    mo.observe(document.body, { childList: true, subtree: true });

    return () => {
      io.disconnect();
      mo.disconnect();
    };
  }, [property]);

  return null;
}
