/**
 * Serves the org-admin SPA (built by SvelteKit via `admin-web/build/`) and
 * the SPA index fallback for client-side routes under `/admin/*`.
 *
 * The SvelteKit project lives in `hub/admin-web/`. Run `npm run build` there
 * to produce the static output in `admin-web/build/`. In development, use
 * `npm run dev` in `admin-web/` which proxies `/api` and `/auth` to the Hub.
 *
 * Override the UI directory with `CPH_ADMIN_UI_DIR` env if needed.
 */
import { readFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, extname, join, resolve as resolvePath } from "node:path";
import type { FastifyInstance } from "fastify";

const MIME: Record<string, string> = {
  ".html": "text/html; charset=utf-8",
  ".js": "text/javascript; charset=utf-8",
  ".mjs": "text/javascript; charset=utf-8",
  ".css": "text/css; charset=utf-8",
  ".svg": "image/svg+xml",
  ".ico": "image/x-icon",
  ".png": "image/png",
  ".jpg": "image/jpeg",
  ".woff": "font/woff",
  ".woff2": "font/woff2",
  ".json": "application/json; charset=utf-8",
  ".txt": "text/plain; charset=utf-8",
};

function resolveUiDir(): string {
  const override = process.env["CPH_ADMIN_UI_DIR"];
  if (override && override.trim() !== "") return resolvePath(override);
  const here = dirname(fileURLToPath(import.meta.url));
  return resolvePath(join(here, "..", "..", "admin-web", "build"));
}

export async function registerStaticSpa(app: FastifyInstance): Promise<void> {
  const uiDir = resolveUiDir();
  if (!existsSync(join(uiDir, "index.html"))) {
    app.log.warn(
      { uiDir },
      "admin-web/build not found; SPA shell disabled. Run `npm run build` in admin-web/ to enable. Org admin APIs remain fully functional.",
    );
    return;
  }
  const indexHtml = await readFile(join(uiDir, "index.html"), "utf8");

  // SvelteKit static assets (_app/*, favicon, etc.)
  app.get("/_app/*", async (request, reply) => {
    const rel = (request.params as { "*": string })["*"];
    const safe = rel.split("/").filter((p) => p !== ".." && p !== "").join("/");
    try {
      const buf = await readFile(join(uiDir, "_app", safe));
      const mime = MIME[extname(safe)] ?? "application/octet-stream";
      return reply.type(mime).send(buf);
    } catch {
      return reply.status(404).send({ error: { code: "not_found", message: "asset not found" } });
    }
  });

  // Other top-level static assets (favicon.svg, robots.txt, etc.)
  app.get("/favicon.svg", async (_request, reply) => {
    try {
      const buf = await readFile(join(uiDir, "favicon.svg"));
      return reply.type("image/svg+xml").send(buf);
    } catch {
      return reply.status(404).send();
    }
  });

  // SPA client-side route fallback. Auth registers `/admin/login` first so it
  // takes precedence; everything else under /admin/* serves the index so
  // SvelteKit's client-side router can resolve the view.
  app.get("/admin", async (_request, reply) => {
    return reply.type("text/html; charset=utf-8").send(indexHtml);
  });
  app.get("/admin/*", async (_request, reply) => {
    return reply.type("text/html; charset=utf-8").send(indexHtml);
  });
}
