import { afterAll, expect, test } from "bun:test";
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
import { get } from "node:http";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { definePlugin } from "@wrnexus/plugin";
import { startServer } from "../src/index.ts";

const root = mkdtempSync(join(tmpdir(), "wrnexus-plugin-config-"));
const appDir = join(root, "app");
const routeFile = join(root, "config-probe.ts");
const runtimeKey = `@wrnexus/dev-server:test:plugin-config:${crypto.randomUUID()}`;

mkdirSync(appDir, { recursive: true });
writeFileSync(join(root, "package.json"), JSON.stringify({ name: "plugin-config-lifecycle-test" }));
writeFileSync(
  routeFile,
  `
export function GET() {
  return Response.json({
    value: globalThis[Symbol.for(${JSON.stringify(runtimeKey)})],
  });
}
`,
);

afterAll(() => {
  delete (globalThis as Record<PropertyKey, unknown>)[Symbol.for(runtimeKey)];
  rmSync(root, { recursive: true, force: true });
});

function getJson(url: string): Promise<{ status: number | undefined; body: unknown }> {
  return new Promise((resolve, reject) => {
    const request = get(url, (response) => {
      const chunks: Buffer[] = [];
      response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
      response.on("end", () => {
        try {
          resolve({
            status: response.statusCode,
            body: JSON.parse(Buffer.concat(chunks).toString("utf8")),
          });
        } catch (error) {
          reject(error);
        }
      });
    });
    request.on("error", reject);
  });
}

test("startServer configures plugins once with the complete application config", async () => {
  let configureCalls = 0;
  const plugin = definePlugin({
    name: "plugin-config-lifecycle-test",
    configure(config) {
      configureCalls += 1;
      (globalThis as Record<PropertyKey, unknown>)[Symbol.for(runtimeKey)] =
        config.lifecycleSentinel;
    },
    routeEntries: [{ kind: "api", path: "/api/config-probe", entry: routeFile }],
  });

  const server = await startServer({
    appDir,
    appConfig: { lifecycleSentinel: "configured" },
    plugins: plugin,
    hostname: "127.0.0.1",
    port: 0,
    mode: "development",
    hmr: false,
  });

  try {
    const response = await getJson(`${server.url}/api/config-probe`);
    expect(response.status).toBe(200);
    expect(response.body).toEqual({ value: "configured" });
    expect(configureCalls).toBe(1);
  } finally {
    server.stop();
  }
});
