"use client";

/**
 * Live Preview — broken-link inspector
 * ────────────────────────────────────
 * Loads the customer's website in an iframe with a meSEO query param
 * that tells the Site Tag (public/t.js) to switch on its broken-link
 * inspect overlay. The side panel lists every broken link we know
 * about for the target page; clicking one selects it (the Site Tag
 * receives no message back — selection is purely visual on this side,
 * the overlay on the iframe already paints every match).
 *
 * Trust model:
 *  - The iframe is loaded with sandbox="allow-scripts allow-same-origin"
 *    so it can run the Site Tag but can't call parent APIs beyond
 *    postMessage. We don't rely on anything it sends us beyond a
 *    "ready" signal used to flip the loading state.
 *  - The broken-link data comes from our own /api/site-tag/page-links
 *    GET handler, authed via brandId in the URL.
 */

import { useSearchParams } from "next/navigation";
import { useEffect, useMemo, useRef, useState, Suspense } from "react";
import { ArrowLeft, ExternalLink, AlertTriangle, CheckCircle2, Loader2 } from "lucide-react";

interface BrokenLinkRow {
  destinationUrl: string;
  linkText: string;
  elementType: string;
  selector: string;
  parentSection: string;
  statusCode: number;
  detectedAt: string;
}

// ─── Preview content ────────────────────────────────────────────────────────

function PreviewContent() {
  const params = useSearchParams();
  const targetUrl = params.get("url") || "";
  const brandId = params.get("brandId") || "";

  const [brokenLinks, setBrokenLinks] = useState<BrokenLinkRow[]>([]);
  const [status, setStatus] = useState<"loading" | "ready" | "error" | "waiting-iframe" | "overlay-failed">("loading");
  const [selectedIdx, setSelectedIdx] = useState<number | null>(null);
  const [iframeError, setIframeError] = useState(false);
  const iframeRef = useRef<HTMLIFrameElement>(null);

  // Resolve the path portion of the target URL — the API stores paths
  // (not full URLs) so we need to extract /about from https://foo.com/about.
  const targetPath = useMemo(() => {
    try { return new URL(targetUrl).pathname; }
    catch { return targetUrl.startsWith("/") ? targetUrl : "/"; }
  }, [targetUrl]);

  // Build the iframe src via the server-side proxy so X-Frame-Options
  // and CSP frame-ancestors headers are stripped. Falls back to direct
  // load if the proxy URL can't be constructed.
  const iframeSrc = useMemo(() => {
    if (!targetUrl || !brandId) return "";
    const inspectUrl = `${targetUrl}${targetUrl.includes("?") ? "&" : "?"}__meseo_inspect=broken-links`;
    return `/api/preview/proxy?url=${encodeURIComponent(inspectUrl)}&brandId=${encodeURIComponent(brandId)}`;
  }, [targetUrl, brandId]);

  // Load broken-link records for this page.
  useEffect(() => {
    if (!targetUrl || !brandId) {
      setStatus("error");
      return;
    }
    let cancelled = false;
    setStatus("loading");

    (async () => {
      try {
        const res = await fetch(
          `/api/site-tag/page-links?brandId=${encodeURIComponent(brandId)}&pageUrl=${encodeURIComponent(targetPath)}`,
        );
        if (!res.ok) {
          if (!cancelled) setStatus("error");
          return;
        }
        const data = await res.json();
        if (cancelled) return;
        const rows: BrokenLinkRow[] = Array.isArray(data?.brokenLinks) ? data.brokenLinks : [];
        setBrokenLinks(rows);
        setStatus(rows.length > 0 ? "waiting-iframe" : "ready");
      } catch {
        if (!cancelled) setStatus("error");
      }
    })();

    return () => { cancelled = true; };
  }, [brandId, targetUrl, targetPath]);

  // Wait for the iframe's Site Tag to postMessage that it's painted its
  // overlay — this gives us a trustworthy "ready" signal (rather than
  // guessing from iframe load events, which fire before the overlay
  // paints).
  useEffect(() => {
    function onMessage(ev: MessageEvent) {
      if (!ev?.data || typeof ev.data !== "object") return;
      const msg = ev.data as { type?: string; brokenCount?: number };
      if (msg.type === "meseo-inspect-ready") {
        setStatus("ready");
      }
    }
    window.addEventListener("message", onMessage);
    return () => window.removeEventListener("message", onMessage);
  }, []);

  // Push broken-link data to the iframe so its overlay can paint even
  // when the Site Tag can't fetch from the API (MESEO_ORIGIN empty,
  // CORS blocked, etc.). We send after a short delay to let the
  // iframe's message listener initialize.
  const iframeLoadedRef = useRef(false);
  useEffect(() => {
    if (status !== "waiting-iframe" || brokenLinks.length === 0) return;
    function pushData() {
      const iframe = iframeRef.current;
      if (!iframe?.contentWindow) return;
      iframe.contentWindow.postMessage(
        { type: "meseo-inspect-paint", brokenLinks },
        "*",
      );
    }
    // Push once on entering waiting-iframe, and again after iframe
    // reports load (the first push may arrive before the listener).
    const t1 = setTimeout(pushData, 1500);
    const t2 = setTimeout(pushData, 4000);
    function onLoad() { iframeLoadedRef.current = true; setTimeout(pushData, 2500); }
    const iframe = iframeRef.current;
    iframe?.addEventListener("load", onLoad);
    return () => { clearTimeout(t1); clearTimeout(t2); iframe?.removeEventListener("load", onLoad); };
  }, [status, brokenLinks]);

  // Timeout: if the overlay hasn't painted after 10s, fall back to
  // list-only mode. This covers: Site Tag not installed, iframe blocked
  // by X-Frame-Options, fetch failure inside the iframe, etc.
  useEffect(() => {
    if (status !== "waiting-iframe") return;
    const timer = setTimeout(() => {
      setStatus((s) => (s === "waiting-iframe" ? "overlay-failed" : s));
    }, 10_000);
    return () => clearTimeout(timer);
  }, [status]);

  // When the user selects a row, tell the iframe to scroll to and
  // strongly highlight that element. Allow in both "ready" and
  // "overlay-failed" states — the latter still has the iframe loaded,
  // so postMessage may work if the Site Tag is present but was slow.
  useEffect(() => {
    if (status !== "ready" && status !== "overlay-failed") return;
    const iframe = iframeRef.current;
    if (!iframe?.contentWindow) return;
    if (selectedIdx == null) {
      iframe.contentWindow.postMessage({ type: "meseo-inspect-clear-focus" }, "*");
      return;
    }
    const record = brokenLinks[selectedIdx];
    if (!record) return;
    // Pass both the index (fast O(1) lookup in the iframe's rendered
    // cache) and the full record (fallback so the Site Tag can re-
    // resolve the element if it wasn't painted on first pass).
    iframe.contentWindow.postMessage(
      {
        type: "meseo-inspect-focus",
        index: selectedIdx,
        record: {
          destinationUrl: record.destinationUrl,
          selector: record.selector,
          elementType: record.elementType,
          statusCode: record.statusCode,
          linkText: record.linkText,
          parentSection: record.parentSection,
        },
      },
      "*",
    );
  }, [selectedIdx, status, brokenLinks]);

  return (
    <div className="h-screen flex flex-col bg-slate-950">
      {/* Toolbar */}
      <header className="h-14 bg-slate-900 border-b border-slate-700 flex items-center px-4 gap-4 shrink-0 z-50">
        <a
          href="/broken-links"
          className="inline-flex items-center gap-1.5 text-xs px-3 py-1.5 bg-slate-800 hover:bg-slate-700 rounded-md text-white font-medium"
        >
          <ArrowLeft className="w-3.5 h-3.5" /> Back
        </a>
        <div className="flex items-center gap-2">
          <div className="w-6 h-6 rounded bg-brand-500 flex items-center justify-center text-white text-xs font-bold">M</div>
          <span className="text-white font-semibold text-sm">Link Inspector</span>
        </div>
        <div className="flex-1 min-w-0">
          <div className="bg-slate-800 rounded-md px-3 py-1.5 text-xs text-slate-300 truncate" title={targetUrl}>
            {targetUrl || "No URL provided"}
          </div>
        </div>
        <div className="flex items-center gap-3 shrink-0">
          <StatusBadge status={status} count={brokenLinks.length} />
          {targetUrl && (
            <a
              href={targetUrl}
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-1 text-xs px-3 py-1.5 bg-slate-800 hover:bg-slate-700 rounded-md text-white font-medium"
            >
              <ExternalLink className="w-3.5 h-3.5" /> Open
            </a>
          )}
        </div>
      </header>

      <div className="flex flex-1 overflow-hidden">
        {/* Side panel */}
        <aside className="w-80 bg-slate-900 border-r border-slate-700 overflow-y-auto shrink-0">
          <div className="px-4 py-3 border-b border-slate-800">
            <h2 className="text-sm font-semibold text-white">
              Broken Links ({brokenLinks.length})
            </h2>
            <p className="text-[11px] text-slate-500 mt-0.5">
              {brokenLinks.length === 0
                ? status === "loading"
                  ? "Checking this page…"
                  : "No broken links found on this page."
                : status === "overlay-failed"
                  ? "Overlay unavailable — use this list to review broken links"
                  : "Click a row to locate it on the page"}
            </p>
          </div>

          {status === "loading" && brokenLinks.length === 0 && (
            <div className="px-4 py-8 text-center text-slate-500 text-xs">
              <Loader2 className="w-5 h-5 text-slate-600 mx-auto mb-2 animate-spin" />
              Loading broken-link data…
            </div>
          )}

          {status === "error" && (
            <div className="px-4 py-6 mx-4 mt-3 rounded-md bg-red-950/60 border border-red-900 text-xs text-red-200">
              <AlertTriangle className="w-4 h-4 mb-1" />
              Couldn&apos;t load broken-link data. Check that the brand has the
              Site Tag installed and has reported this page at least once.
            </div>
          )}

          {brokenLinks.length > 0 && (
            <ul className="p-3 space-y-2">
              {brokenLinks.map((link, i) => {
                const isSelected = selectedIdx === i;
                return (
                  <li key={`${link.destinationUrl}-${i}`}>
                    <button
                      type="button"
                      onClick={() => setSelectedIdx(isSelected ? null : i)}
                      className={`w-full text-left rounded-md border px-3 py-2.5 transition-colors ${
                        isSelected
                          ? "bg-red-950/40 border-red-500"
                          : "bg-slate-800 border-slate-700 hover:border-slate-600"
                      }`}
                    >
                      <div className="flex items-center gap-2 mb-1">
                        <span className="text-red-400 text-[10px] font-mono font-bold px-1.5 py-0.5 rounded bg-red-950/60 border border-red-900">
                          {link.statusCode}
                        </span>
                        <span className="text-[10px] text-slate-400 capitalize">
                          {link.elementType || "link"}
                        </span>
                        <span className="text-[10px] text-slate-500">
                          in {link.parentSection || "page"}
                        </span>
                      </div>
                      <div className="text-sm text-white font-medium truncate">
                        &ldquo;{link.linkText || "[no text]"}&rdquo;
                      </div>
                      <div className="text-xs text-red-300 truncate mt-1" title={link.destinationUrl}>
                        → {link.destinationUrl}
                      </div>
                      {isSelected && (
                        <div className="mt-2 pt-2 border-t border-red-900/50 space-y-1.5">
                          <p className="text-[11px] text-slate-300 leading-relaxed">
                            {link.elementType === "img"
                              ? `This image returns HTTP ${link.statusCode}. The file at "${link.destinationUrl}" was deleted or moved. Visitors see a broken image icon instead.`
                              : `This link points to "${link.destinationUrl}" which returns HTTP ${link.statusCode}. Visitors clicking "${link.linkText || "this link"}" will land on an error page.`}
                          </p>
                          <p className="text-[10px] text-amber-400 font-medium">
                            {link.elementType === "img"
                              ? "Fix: Re-upload the image or update the src attribute to a valid URL."
                              : "Fix: Update the href to a valid URL or add a 301 redirect."}
                          </p>
                          {link.selector && (
                            <p className="text-[10px] text-slate-500 font-mono truncate" title={link.selector}>
                              Element: {link.selector}
                            </p>
                          )}
                        </div>
                      )}
                    </button>
                  </li>
                );
              })}
            </ul>
          )}
        </aside>

        {/* Iframe pane */}
        <main className="flex-1 relative bg-white">
          {iframeSrc ? (
            <>
              <iframe
                ref={iframeRef}
                src={iframeSrc}
                className="w-full h-full border-0"
                sandbox="allow-scripts allow-same-origin allow-popups allow-forms"
                title="Live site preview"
                onError={() => setIframeError(true)}
              />
              {(status === "loading" || status === "waiting-iframe") && (
                <div className="absolute inset-0 flex items-center justify-center bg-white/80 backdrop-blur-sm pointer-events-none">
                  <div className="bg-white rounded-lg shadow-lg px-5 py-4 border border-slate-200 text-sm text-slate-700 flex items-center gap-2">
                    <Loader2 className="w-4 h-4 animate-spin text-brand-600" />
                    {status === "loading" ? "Loading broken-link data…" : "Painting overlay on the live page…"}
                  </div>
                </div>
              )}
              {(status === "overlay-failed" || iframeError) && brokenLinks.length > 0 && (
                <div className="absolute top-3 left-1/2 -translate-x-1/2 z-10">
                  <div className="bg-amber-50 border border-amber-200 rounded-lg px-4 py-2.5 shadow-lg flex items-center gap-2 text-xs text-amber-800">
                    <AlertTriangle className="w-3.5 h-3.5 text-amber-600 shrink-0" />
                    <span>
                      {iframeError
                        ? "This site blocked embedding. Broken links are listed in the side panel."
                        : "Overlay painting unavailable in preview mode. Broken links are listed in the side panel."}
                    </span>
                  </div>
                </div>
              )}
            </>
          ) : (
            <div className="h-full flex items-center justify-center text-slate-500 text-sm">
              No preview URL provided.
            </div>
          )}
        </main>
      </div>
    </div>
  );
}

// ─── Small bits ─────────────────────────────────────────────────────────────

function StatusBadge({
  status,
  count,
}: {
  status: "loading" | "ready" | "error" | "waiting-iframe" | "overlay-failed";
  count: number;
}) {
  if (status === "error") {
    return (
      <span className="inline-flex items-center gap-1 text-xs font-medium text-red-300">
        <AlertTriangle className="w-3.5 h-3.5" /> Load failed
      </span>
    );
  }
  if (status === "loading") {
    return (
      <span className="inline-flex items-center gap-1 text-xs font-medium text-slate-400">
        <Loader2 className="w-3.5 h-3.5 animate-spin" /> Checking…
      </span>
    );
  }
  if (status === "waiting-iframe") {
    return (
      <span className="inline-flex items-center gap-1 text-xs font-medium text-slate-400">
        <Loader2 className="w-3.5 h-3.5 animate-spin" /> Painting…
      </span>
    );
  }
  if (count === 0) {
    return (
      <span className="inline-flex items-center gap-1 text-xs font-medium text-emerald-400">
        <CheckCircle2 className="w-3.5 h-3.5" /> No broken links
      </span>
    );
  }
  return (
    <span className="inline-flex items-center gap-1 text-xs font-semibold text-red-400">
      <AlertTriangle className="w-3.5 h-3.5" />
      {count} broken link{count !== 1 ? "s" : ""}
      {status === "overlay-failed" && <span className="text-amber-400 font-normal">(list only)</span>}
    </span>
  );
}

// ─── Page wrapper — Suspense is required by useSearchParams ─────────────────

export default function PreviewPage() {
  return (
    <Suspense
      fallback={
        <div className="h-screen bg-slate-950 flex items-center justify-center text-white text-sm">
          <Loader2 className="w-5 h-5 animate-spin mr-2" /> Loading preview…
        </div>
      }
    >
      <PreviewContent />
    </Suspense>
  );
}
