/**
 * GET /api/preview/embed?u=<encoded https URL>
 *
 * Experimental: authenticated HTML proxy that injects vibn-preview-bridge.js + `<base>`.
 * Serving tunnel markup under the Vibn origin breaks Next.js and similar SPAs
 * (History/replaceState + asset CORS). Use direct iframe tunnel URLs by default;
 * enable via NEXT_PUBLIC_USE_PREVIEW_EMBED_PROXY only for simple static previews.
 */
import { NextResponse } from "next/server";
import { authSession } from "@/lib/auth/session-server";
import { serverPreviewHostnameAllowed } from "@/lib/preview-embed-allowlist";

export const runtime = "nodejs";

const MAX_HTML_CHARS = 2_500_000;

function escapeHtmlAttr(s: string): string {
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
}

function requestOrigin(req: Request): string {
  const self = new URL(req.url);
  const xfHost = req.headers.get("x-forwarded-host");
  const xfProto = req.headers.get("x-forwarded-proto");
  if (xfHost) {
    return `${xfProto ?? "https"}://${xfHost.split(",")[0]?.trim() ?? xfHost}`;
  }
  return self.origin;
}

function directoryBasePath(pathname: string): string {
  if (pathname.endsWith("/")) return pathname || "/";
  const i = pathname.lastIndexOf("/");
  if (i <= 0) return "/";
  return pathname.slice(0, i + 1);
}

/**
 * GET /api/preview/embed?u=<encoded https URL>
 * Authenticated HTML proxy that injects vibn-preview-bridge.js + <base> so element-pick works same-origin.
 */
export async function GET(req: Request) {
  const session = await authSession();
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  let target: URL;
  try {
    const { searchParams } = new URL(req.url);
    const raw = searchParams.get("u");
    if (!raw?.trim()) {
      return NextResponse.json({ error: "Missing u" }, { status: 400 });
    }
    target = new URL(raw);
  } catch {
    return NextResponse.json({ error: "Invalid URL" }, { status: 400 });
  }

  if (!serverPreviewHostnameAllowed(target.hostname, target.protocol)) {
    return NextResponse.json({ error: "Host not allowed for preview embed" }, { status: 403 });
  }

  let res: Response;
  try {
    res = await fetch(target.toString(), {
      redirect: "follow",
      signal: AbortSignal.timeout(25_000),
      headers: {
        Accept: "text/html,application/xhtml+xml;q=0.9,*/*;q=0.8",
        "User-Agent": "VibnPreviewEmbed/1.0",
      },
    });
  } catch {
    return NextResponse.json({ error: "Failed to fetch preview" }, { status: 502 });
  }

  const finalUrl = new URL(res.url);
  if (!serverPreviewHostnameAllowed(finalUrl.hostname, finalUrl.protocol)) {
    return NextResponse.json({ error: "Redirect led to disallowed host" }, { status: 403 });
  }

  const ct = res.headers.get("content-type") ?? "";
  if (!/html/i.test(ct)) {
    return NextResponse.json({ error: "Not HTML" }, { status: 415 });
  }

  let html = await res.text();
  if (html.length > MAX_HTML_CHARS) {
    return NextResponse.json({ error: "HTML too large" }, { status: 413 });
  }

  const appOrigin = requestOrigin(req);
  const bridgeSrc = `${appOrigin}/vibn-preview-bridge.js`;
  const baseHref = `${finalUrl.origin}${directoryBasePath(finalUrl.pathname)}`;

  html = html.replace(/<meta[^>]*http-equiv\s*=\s*["']Content-Security-Policy["'][^>]*>/gi, "");
  html = html.replace(/<base\s[^>]*>/gi, "");

  const baseTag = `<base href="${escapeHtmlAttr(baseHref)}">`;
  if (/<head[^>]*>/i.test(html)) {
    html = html.replace(/<head[^>]*>/i, `$&${baseTag}`);
  } else {
    html = `<!DOCTYPE html><html><head>${baseTag}<meta charset="utf-8"/></head><body>${html}</body></html>`;
  }

  const scriptTag = `<script src="${escapeHtmlAttr(bridgeSrc)}" defer><\/script>`;
  if (/<\/body>/i.test(html)) {
    html = html.replace(/<\/body>/i, `${scriptTag}</body>`);
  } else {
    html += scriptTag;
  }

  return new NextResponse(html, {
    status: 200,
    headers: {
      "Content-Type": "text/html; charset=utf-8",
      "Cache-Control": "private, no-store",
      "X-Robots-Tag": "noindex, nofollow",
    },
  });
}
