"use client";

import { useEffect, useRef, useState } from "react";
import { useGoogleAds } from "@/context/GoogleAdsContext";

declare global {
  interface Window {
    adsbygoogle: Record<string, unknown>[];
  }
}

// Deduplicate external script loads across the whole document lifetime.
// Maps src URL → Promise<void> so concurrent callers share the same load.
const scriptLoaders = new Map<string, Promise<void>>();

function loadScript(src: string): Promise<void> {
  if (scriptLoaders.has(src)) return scriptLoaders.get(src)!;

  const existing = document.querySelector<HTMLScriptElement>(
    `script[src="${src}"]`,
  );
  if (existing) {
    const p = Promise.resolve();
    scriptLoaders.set(src, p);
    return p;
  }

  const p = new Promise<void>((resolve) => {
    const el = document.createElement("script");
    el.src = src;
    el.async = true;
    el.crossOrigin = "anonymous";
    el.onload = () => resolve();
    el.onerror = () => {
      console.error(`[GoogleAd] Failed to load script: ${src}`);
      resolve(); // resolve so downstream inline code can still attempt
    };
    document.head.appendChild(el);
  });

  scriptLoaders.set(src, p);
  return p;
}

/* ── Placeholder shown when ad is blocked / unfilled / on localhost ─────── */
function AdPlaceholder({ placement }: { placement: string }) {
  return (
    <div
      style={{
        width: "100%",
        minHeight: 90,
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        gap: 4,
        background: "var(--btn-ghost, rgba(0,0,0,0.03))",
        border: "1px dashed var(--border, #e0e0e0)",
        borderRadius: 8,
        color: "var(--text-muted, #aaa)",
        fontSize: 11,
        fontWeight: 600,
        letterSpacing: "0.07em",
        textTransform: "uppercase",
        userSelect: "none",
      }}
      aria-hidden="true"
      data-ad-placeholder={placement}
    >
      <svg
        width="16"
        height="16"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
        strokeLinejoin="round"
        style={{ opacity: 0.5 }}
      >
        <rect x="2" y="3" width="20" height="14" rx="2" />
        <path d="M8 21h8M12 17v4" />
      </svg>
      Advertisement
    </div>
  );
}

type AdStatus = "loading" | "filled" | "failed";

export function GoogleAd({ placement }: { placement: string }) {
  const { getPlacement, isLoading } = useGoogleAds();
  const containerRef = useRef<HTMLDivElement>(null);
  const [status, setStatus] = useState<AdStatus>("loading");

  const ad = getPlacement(placement);

  useEffect(() => {
    const container = containerRef.current;
    if (!ad || !container) return;

    // StrictMode guard: React 18 keeps the DOM node across double-invoke.
    // If the container already carries this ad's id, the effect has already run.
    if (container.dataset.adId === String(ad.id)) return;

    // Clear any previous ad and reset status
    container.innerHTML = "";
    container.dataset.adId = String(ad.id);
    setStatus("loading");

    // Parse ad_code into script and non-script nodes
    const tmp = document.createElement("div");
    tmp.innerHTML = ad.ad_code;

    const externalSrcs: string[] = [];
    const inlineCodes: string[] = [];

    Array.from(tmp.childNodes).forEach((node) => {
      if (node.nodeName === "SCRIPT") {
        const s = node as HTMLScriptElement;
        const src = s.getAttribute("src");
        if (src) {
          externalSrcs.push(src);
        } else if (s.textContent?.trim()) {
          inlineCodes.push(s.textContent.trim());
        }
      } else {
        container.appendChild(node.cloneNode(true));
      }
    });

    let observer: MutationObserver | null = null;
    let fallback: ReturnType<typeof setTimeout> | null = null;

    const cleanup = () => {
      observer?.disconnect();
      if (fallback) clearTimeout(fallback);
    };

    (async () => {
      // 1. Load external scripts (deduplicated)
      for (const src of externalSrcs) {
        await loadScript(src);
      }

      // 2. Run inline scripts (the adsbygoogle.push({}))
      for (const code of inlineCodes) {
        try {
          // eslint-disable-next-line no-new-func
          new Function(code)();
        } catch (err) {
          console.error(
            `[GoogleAd] placement="${placement}" — inline script error:`,
            err,
          );
          setStatus("failed");
          return;
        }
      }

      // 3. Watch the <ins> for AdSense fill confirmation
      const ins = container.querySelector("ins");

      if (!ins) {
        // No <ins> element — treat as filled (custom HTML ad)
        setStatus("filled");
        return;
      }

      observer = new MutationObserver(() => {
        const adStatus = ins.getAttribute("data-adsbygoogle-status");
        if (adStatus) {
          cleanup();
          // Wait briefly for AdSense to size the iframe
          setTimeout(() => {
            const filled = ins.offsetHeight > 0;
            if (!filled) {
              console.warn(
                `[GoogleAd] placement="${placement}" — ad not filled.`,
                "Note: Google AdSense does not serve ads on localhost.",
                "Deploy to your approved domain to see live ads.",
              );
            }
            setStatus(filled ? "filled" : "failed");
          }, 200);
        }
      });

      observer.observe(ins, {
        attributes: true,
        attributeFilter: ["data-adsbygoogle-status"],
      });

      // 4. Fallback: AdSense never responded within 6 seconds
      fallback = setTimeout(() => {
        console.warn(
          `[GoogleAd] placement="${placement}" — timed out (6s). Ad blocked or not filled.`,
        );
        setStatus("failed");
        observer?.disconnect();
      }, 6000);
    })();

    return cleanup;
  }, [ad, placement]);

  // No placement configured by admin → render nothing (no placeholder)
  if (isLoading || !ad) return null;

  return (
    <div style={{ width: "100%", overflow: "hidden" }}>
      {/* Container stays mounted so the ref is always valid */}
      <div
        ref={containerRef}
        style={{ display: status === "failed" ? "none" : "block", width: "100%" }}
        data-ad-placement={placement}
      />
      {status === "failed" && <AdPlaceholder placement={placement} />}
    </div>
  );
}
