"use client";

import { useEffect, useRef } from "react";
import AppImage from "@/components/ui/AppImage";

interface Ad {
  slug?: string;
  label: string;
  size: string;
  src?: string;
  alt?: string;
  click_url?: string;
}

// Banner renderer with impression + click tracking. Impressions are logged
// twice per visible render via navigator.sendBeacon (no fetch promise
// awaited, no impact on paint):
//   1. on mount — guarantees a count even if the user never sees the banner
//      (gross-count policy, intentional)
//   2. on viewport intersection (≥500ms, threshold 0.5) — viewport=true,
//      gives clients who care a "viewable" subset
//
// Clicks always route through /r/{slug} which logs server-side then 302s
// to the click_url stored in bb.banner_creatives. We do NOT also log on
// the link's onClick — the /r/ route is the single source of truth.

export default function AdImage({
  ad,
  page,
  priority,
}: {
  ad: Ad;
  page?: string;
  priority?: boolean;
}) {
  const containerRef = useRef<HTMLDivElement>(null);
  const beaconMount = useRef(false);
  const beaconViewport = useRef(false);

  useEffect(() => {
    if (!ad.src || !ad.slug) return;

    if (!beaconMount.current) {
      beaconMount.current = true;
      sendImpression(ad.slug, page, false);
    }

    const el = containerRef.current;
    if (!el || beaconViewport.current) return;
    const observer = new IntersectionObserver(
      (entries) => {
        for (const e of entries) {
          if (e.isIntersecting && !beaconViewport.current) {
            beaconViewport.current = true;
            sendImpression(ad.slug!, page, true);
            observer.disconnect();
            return;
          }
        }
      },
      { threshold: 0.5 },
    );
    observer.observe(el);
    return () => observer.disconnect();
  }, [ad.src, ad.slug, page]);

  if (!ad.src) return null;

  const [w, h] = ad.size.split("x").map((n) => parseInt(n, 10));
  const clickHref = ad.slug ? `/r/${ad.slug}` : ad.click_url || "";

  return (
    <div ref={containerRef} className="ad-container">
      {clickHref ? (
        <a href={clickHref} target="_blank" rel="sponsored noopener noreferrer">
          <AppImage src={ad.src} alt={ad.alt || ad.label} width={w} height={h} priority={priority} />
        </a>
      ) : (
        <AppImage src={ad.src} alt={ad.alt || ad.label} width={w} height={h} priority={priority} />
      )}
    </div>
  );
}

function sendImpression(slug: string, page: string | undefined, viewport: boolean) {
  if (typeof window === "undefined") return;
  // We need the campaign UUID, not the slug, on the wire — but the
  // server-side /api/track/impression endpoint accepts slug-or-uuid and
  // resolves it. To keep payload tiny and avoid leaking IDs, we send
  // slug + the viewport flag.
  const payload = JSON.stringify({
    slug,
    page_path: page || window.location.pathname,
    page_url: window.location.href,
    viewport,
  });
  try {
    const ok =
      typeof navigator.sendBeacon === "function" &&
      navigator.sendBeacon(
        "/api/track/impression",
        new Blob([payload], { type: "application/json" }),
      );
    if (ok) return;
  } catch {
    // fall through to fetch
  }
  fetch("/api/track/impression", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: payload,
    keepalive: true,
  }).catch(() => undefined);
}
