import { afterEach, expect, test } from "bun:test";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { buildRouter } from "@wrnexus/router";
import { v } from "@wrnexus/validation";
import { createHandlers, type RuntimeDeps } from "../src/runtime.ts";

const roots: string[] = [];
afterEach(() => roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true })));
const server = { upgrade: () => false };

test("server actions validate, enforce CSRF, invalidate, and progressively enhance forms", async () => {
  const root = mkdtempSync(join(tmpdir(), "wrnexus-action-runtime-"));
  roots.push(root);
  const app = join(root, "app");
  mkdirSync(join(app, "pages"), { recursive: true });
  writeFileSync(join(app, "pages", "users.ts"), "export default () => '';");
  const router = buildRouter(app);
  const schema = v.object({ name: v.string().min(2) });
  const security: Record<string, string> = {};
  let authenticated = false;
  let granted = false;
  const handlers = createHandlers({
    mode: "production",
    hmr: false,
    router,
    loadModule: async () => ({
      default: () => `<form method="post" data-wrn-action="createUser"><input name="name"></form>`,
      __wrnexusActions: {
        createUser: {
          schema,
          run: (input: { name: string }, ctx: { locals: Record<string, unknown> }) => {
            ctx.locals.__wrnexusInvalidatedTags = ["users", "users"];
            return { id: `user-${input.name}` };
          },
        },
      },
      __wrnexusSecurity: security,
    }),
    getMiddleware: async () => [
      (ctx, next) => {
        if (authenticated) ctx.user = { id: "operator" };
        ctx.locals.permissions = granted ? ["users.create"] : [];
        return next();
      },
    ],
    assets: { serve: async () => null },
  } satisfies RuntimeDeps);

  const page = await handlers.fetch(new Request("https://example.test/users"), server);
  const html = await page!.text();
  expect(html).toContain('name="_csrf"');
  expect(html).toContain("/__wrnexus/actions.js");
  const cookie = page!.headers.get("set-cookie")!;
  const token = /wire-csrf=([^;]+)/.exec(cookie)?.[1];
  if (!token) throw new Error("expected CSRF cookie");

  const invalid = await handlers.fetch(
    new Request("https://example.test/users", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        accept: "application/json",
        cookie,
        "x-wrnexus-action": "createUser",
        "x-csrf-token": token,
      },
      body: JSON.stringify({ name: "x" }),
    }),
    server,
  );
  expect(invalid?.status).toBe(422);
  expect(await invalid?.json()).toMatchObject({ errors: { name: expect.any(String) } });

  const noCsrf = await handlers.fetch(
    new Request("https://example.test/users", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        accept: "application/json",
        cookie,
        "x-wrnexus-action": "createUser",
      },
      body: JSON.stringify({ name: "Ada" }),
    }),
    server,
  );
  expect(noCsrf?.status).toBe(403);

  const success = await handlers.fetch(
    new Request("https://example.test/users", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        accept: "application/json",
        cookie,
        "x-wrnexus-action": "createUser",
        "x-csrf-token": token,
      },
      body: JSON.stringify({ name: "Ada" }),
    }),
    server,
  );
  expect(await success?.json()).toEqual({
    ok: true,
    data: { id: "user-Ada" },
    invalidated: ["users"],
  });

  security.auth = "required";
  expect(
    (
      await handlers.fetch(
        new Request("https://example.test/users", {
          method: "POST",
          headers: {
            "content-type": "application/json",
            accept: "application/json",
            cookie,
            "x-wrnexus-action": "createUser",
            "x-csrf-token": token,
          },
          body: JSON.stringify({ name: "Ada" }),
        }),
        server,
      )
    )?.status,
  ).toBe(401);
  authenticated = true;
  security.permission = "users.create";
  expect(
    (
      await handlers.fetch(
        new Request("https://example.test/users", {
          method: "POST",
          headers: {
            "content-type": "application/json",
            accept: "application/json",
            cookie,
            "x-wrnexus-action": "createUser",
            "x-csrf-token": token,
          },
          body: JSON.stringify({ name: "Ada" }),
        }),
        server,
      )
    )?.status,
  ).toBe(403);
  granted = true;

  const form = new FormData();
  form.set("_wrnexus_action", "createUser");
  form.set("_csrf", token);
  form.set("name", "Grace");
  const progressive = await handlers.fetch(
    new Request("https://example.test/users", {
      method: "POST",
      headers: { cookie, origin: "https://example.test" },
      body: form,
    }),
    server,
  );
  expect(progressive?.status).toBe(303);
  expect(progressive?.headers.get("location")).toBe("/users");
});
