import index from "./index.html";
import { dirname, join } from "node:path";
import { mkdir } from "node:fs/promises";
import { dataPath } from "../../deployPaths";
import { isSafeStem, jsonError, withAuth } from "../../security";

export const workerPath = new URL(
  import.meta.resolve("pdfjs-dist/build/pdf.worker.mjs"),
).pathname;

const TEMPLATE_PATH =
  process.env.BMP_TEMPLATE_PATH ??
  dataPath(join(import.meta.dir, "template.json"), "templatebuilder", "template.json");

await mkdir(dirname(TEMPLATE_PATH), { recursive: true });

async function loadTemplate(): Promise<Record<string, unknown>> {
  const file = Bun.file(TEMPLATE_PATH);
  if (!(await file.exists())) return {};
  return file.json();
}

export const routes = {
  "/builder": {
    GET: withAuth(async () => index),
  },

  "/api/save": {
    POST: withAuth(async (req: Request) => {
      let data;
      try {
        data = await req.json();
      } catch {
        return jsonError("Expected JSON body", 400);
      }
      if (!isSafeTemplate(data)) {
        return jsonError("Template contains unsafe keys or too many fields", 400);
      }
      await Bun.write(TEMPLATE_PATH, JSON.stringify(data, null, 2));
      return Response.json({ ok: true });
    }, {
      csrf: true,
      limit: { key: "template-save", max: 20, windowMs: 60_000 },
    }),
  },

  "/api/load": {
    GET: withAuth(async () => {
      return Response.json(await loadTemplate());
    }),
  },
} as const;

function isSafeTemplate(value: unknown): value is Record<string, unknown> {
  let fieldCount = 0;

  function visit(node: unknown, depth: number): boolean {
    if (depth > 8 || typeof node !== "object" || node === null || Array.isArray(node)) {
      return false;
    }
    for (const [key, child] of Object.entries(node as Record<string, unknown>)) {
      if (!/^[a-zA-Z0-9_-]{1,80}$/.test(key)) return false;
      if (typeof child === "string") {
        fieldCount += 1;
        if (child.length > 200 || fieldCount > 250) return false;
        continue;
      }
      if (typeof child === "object" && child !== null && "fieldName" in child) {
        fieldCount += 1;
        if (fieldCount > 250 || !isSafeFieldObject(child)) return false;
        continue;
      }
      if (!visit(child, depth + 1)) return false;
    }
    return true;
  }

  return visit(value, 0);
}

function isSafeFieldObject(value: object): boolean {
  const field = value as Record<string, unknown>;
  if (typeof field.fieldName !== "string" || field.fieldName.length > 200) return false;
  if (field.label != null && (typeof field.label !== "string" || field.label.length > 300)) return false;
  if (field.antwortFormat != null && field.antwortFormat !== "einzelfrage" && field.antwortFormat !== "mehrfachfrage_ein_antwortfeld") {
    return false;
  }
  if (field.fragen != null) {
    if (!Array.isArray(field.fragen) || field.fragen.length > 25) return false;
    for (const frage of field.fragen) {
      if (typeof frage !== "object" || frage === null) return false;
      const item = frage as Record<string, unknown>;
      if (typeof item.text !== "string" || item.text.length > 1000) return false;
      if (item.id != null && (typeof item.id !== "string" || !isSafeStem(item.id))) return false;
    }
  }
  return true;
}
