import type { Route } from "./+types/recipe-import";
import {
  importPublicPage,
  PublicPageError,
} from "~/features/recipe-import/server/public-page.server";
const headers = {
  "Cache-Control": "private, no-store",
  "Content-Type": "application/json; charset=utf-8",
  "Referrer-Policy": "no-referrer",
  "X-Content-Type-Options": "nosniff",
  "X-Robots-Tag": "noindex, nofollow, noarchive",
};
export function loader() {
  return Response.json(
    { error: "Use POST to import a recipe page." },
    { status: 405, headers: { ...headers, Allow: "POST" } },
  );
}
export async function action({ request }: Route.ActionArgs) {
  try {
    if (request.method !== "POST") return loader();
    const origin = request.headers.get("origin");
    const publicOrigins = [
      "https://www.bookify.com",
      "https://bookify.com",
      "https://camps.bookify.com",
      "https://meetings.bookify.com",
    ];
    if (
      origin &&
      origin !== new URL(request.url).origin &&
      !publicOrigins.includes(origin)
    )
      throw new PublicPageError("Open recipe imports on this website.", 403);
    if (!request.headers.get("content-type")?.startsWith("application/json"))
      throw new PublicPageError("Send a JSON recipe URL.");
    const reader = request.body?.getReader();
    if (!reader) throw new PublicPageError("Enter a recipe URL.");
    const chunks: Uint8Array[] = [];
    let size = 0;
    let bodyTimer: ReturnType<typeof setTimeout>;
    const bodyTimeout = new Promise<never>((_, reject) => {
      bodyTimer = setTimeout(
        () =>
          reject(new PublicPageError("The import request took too long.", 408)),
        5000,
      );
    });
    try {
      while (true) {
        const part = await Promise.race([reader.read(), bodyTimeout]);
        if (part.done) break;
        size += part.value.length;
        if (size > 4096)
          throw new PublicPageError(
            "The recipe URL request is too large.",
            413,
          );
        chunks.push(part.value);
      }
    } finally {
      clearTimeout(bodyTimer!);
      void reader.cancel().catch(() => {});
    }
    let body: unknown;
    try {
      body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
    } catch {
      throw new PublicPageError("Send a valid recipe URL.");
    }
    if (
      !body ||
      typeof body !== "object" ||
      !("url" in body) ||
      typeof body.url !== "string"
    )
      throw new PublicPageError("Enter a recipe URL.");
    return Response.json(await importPublicPage(body.url), { headers });
  } catch (cause) {
    const error =
      cause instanceof PublicPageError
        ? cause
        : new PublicPageError("This recipe page could not be imported.", 500);
    return Response.json(
      { error: error.message },
      {
        status: error.status,
        headers: {
          ...headers,
          ...(error.status === 429 ? { "Retry-After": "60" } : {}),
        },
      },
    );
  }
}
