import { describe, expect, test } from "bun:test";
import { mkdtempSync, statSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { X509Certificate } from "node:crypto";
import {
  createLocalServicesHandler,
  ensureLocalCertificate,
  startLocalServices,
} from "../src/services.ts";

describe("local production service simulator", () => {
  test("simulates bounded mail, cache, storage, auth and health APIs", async () => {
    const handler = createLocalServicesHandler();
    expect((await handler(new Request("http://local/healthz"))).status).toBe(200);
    expect(
      (
        await handler(
          new Request("http://local/mail", {
            method: "POST",
            body: JSON.stringify({ to: "u@test", subject: "Welcome" }),
          }),
        )
      ).status,
    ).toBe(202);
    expect(await (await handler(new Request("http://local/mail"))).json()).toHaveLength(1);
    await handler(
      new Request("http://local/cache", {
        method: "POST",
        body: JSON.stringify({ key: "user", value: 1 }),
      }),
    );
    expect(await (await handler(new Request("http://local/cache"))).json()).toHaveProperty(
      "user.value",
      1,
    );
    expect(
      (
        await handler(
          new Request("http://local/storage?key=file.txt", { method: "POST", body: "hello" }),
        )
      ).status,
    ).toBe(201);
    expect(await (await handler(new Request("http://local/storage/file.txt"))).text()).toBe(
      "hello",
    );
    expect(
      (
        await handler(
          new Request("http://local/auth", {
            method: "POST",
            body: JSON.stringify({ email: "u@test" }),
          }),
        )
      ).status,
    ).toBe(201);
  });
  test("rejects unsafe storage keys and oversized declared JSON", async () => {
    const handler = createLocalServicesHandler();
    expect(
      (
        await handler(
          new Request("http://local/storage?key=../secret", { method: "POST", body: "bad" }),
        )
      ).status,
    ).toBe(400);
    const response = await handler(
      new Request("http://local/mail", {
        method: "POST",
        body: JSON.stringify({ value: "x".repeat(300_000) }),
      }),
    );
    expect(response.status).toBe(413);
  });
  test("generates and safely reuses a localhost HTTPS certificate", async () => {
    const root = mkdtempSync(join(tmpdir(), "wrnexus-services-cert-"));
    const first = await ensureLocalCertificate(root);
    const certificate = new X509Certificate(first.cert);
    expect(certificate.subjectAltName).toContain("DNS:localhost");
    expect(certificate.subjectAltName).toContain("IP Address:127.0.0.1");
    expect(statSync(first.keyFile).size).toBeGreaterThan(100);
    const second = await ensureLocalCertificate(root);
    expect(second.reused).toBe(true);
    expect(second.cert).toBe(first.cert);
  });
  test("serves the simulator over generated HTTPS", async () => {
    const root = mkdtempSync(join(tmpdir(), "wrnexus-services-tls-"));
    const server = await startLocalServices({ appRoot: root, port: 0, hostname: "127.0.0.1" });
    try {
      const response = await fetch(`https://127.0.0.1:${server.port}/healthz`, {
        tls: { rejectUnauthorized: false },
      });
      expect(response.status).toBe(200);
      expect(await response.json()).toHaveProperty("service", "wrnexus-local-services");
    } finally {
      server.stop(true);
    }
  });
});
