import assert from "node:assert/strict";
import test from "node:test";
import { exactCandidate } from "../src/candidate.mjs";
import { createLabHttpServer } from "../src/http.mjs";

async function withServer(run) {
  const { server } = createLabHttpServer();
  await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
  const { port } = server.address();
  try {
    await run(`http://127.0.0.1:${port}`);
  } finally {
    await new Promise((resolve, reject) =>
      server.close((error) => (error ? reject(error) : resolve())),
    );
  }
}

test("serves the honest overview and exact candidate", async () => {
  await withServer(async (baseUrl) => {
    const overview = await fetch(`${baseUrl}/`);
    assert.equal(overview.status, 200);
    assert.match(await overview.text(), /does not prove/i);

    const instructions = await fetch(`${baseUrl}/README.md`);
    assert.equal(instructions.status, 200);
    assert.match(await instructions.text(), /Partial failure and readback/);

    for (const [path, expectedType] of [
      ["/styles.css", "text/css"],
      ["/assets/field-grid.png", "image/png"],
      ["/assets/lumyn-mark.png", "image/png"],
      ["/CONTRIBUTING.md", "text/markdown"],
      ["/LICENSE", "text/plain"],
      ["/src/service.mjs", "text/javascript"],
      ["/src/sor.mjs", "text/javascript"],
      ["/test/service.test.mjs", "text/javascript"],
      ["/package.json", "application/json"],
    ]) {
      const asset = await fetch(`${baseUrl}${path}`);
      assert.equal(asset.status, 200, `${path} should be served by the local lab`);
      assert.match(asset.headers.get("content-type") ?? "", new RegExp(`^${expectedType}`));
    }

    const traversal = await fetch(`${baseUrl}/src/../auth.mjs`);
    assert.equal(traversal.status, 404);

    const candidateResponse = await fetch(`${baseUrl}/v1/candidate`);
    assert.equal(candidateResponse.status, 200);
    assert.deepEqual(await candidateResponse.json(), exactCandidate);
  });
});

test("executes the API slice and exposes a sanitized telemetry trace", async () => {
  await withServer(async (baseUrl) => {
    const response = await fetch(`${baseUrl}/v1/recommendations`, {
      method: "POST",
      headers: {
        authorization: "Bearer fde-demo-token",
        "content-type": "application/json",
        "idempotency-key": "http-test-key",
        "x-candidate-digest": exactCandidate.digest,
      },
      body: JSON.stringify({
        caseId: "DENIAL-001",
        expectedCaseRevision: 7,
        candidateId: exactCandidate.candidateId,
      }),
    });
    assert.equal(response.status, 201);
    const result = await response.json();
    assert.equal(result.operationId, "op-0001");

    const telemetryResponse = await fetch(`${baseUrl}/v1/telemetry`, {
      headers: { authorization: "Bearer observer-demo-token" },
    });
    assert.equal(telemetryResponse.status, 200);
    const events = await telemetryResponse.json();
    assert.equal(events[0].candidateDigest, exactCandidate.digest);
    assert.equal(JSON.stringify(events).includes("fde-demo-token"), false);
    assert.equal(JSON.stringify(events).includes("modifier25Present"), false);

    const forbiddenSubmission = await fetch(`${baseUrl}/v1/claims/DENIAL-001/submit`, {
      method: "POST",
      headers: { authorization: "Bearer fde-demo-token" },
    });
    assert.equal(forbiddenSubmission.status, 404);
  });
});

test("maps missing authorization and stale revisions to explicit errors", async () => {
  await withServer(async (baseUrl) => {
    const missingAuth = await fetch(`${baseUrl}/v1/cases/DENIAL-001`);
    assert.equal(missingAuth.status, 401);

    const stale = await fetch(`${baseUrl}/v1/recommendations`, {
      method: "POST",
      headers: {
        authorization: "Bearer fde-demo-token",
        "content-type": "application/json",
        "idempotency-key": "stale-http-key",
        "x-candidate-digest": exactCandidate.digest,
      },
      body: JSON.stringify({
        caseId: "DENIAL-001",
        expectedCaseRevision: 6,
        candidateId: exactCandidate.candidateId,
      }),
    });
    assert.equal(stale.status, 409);
    const body = await stale.json();
    assert.equal(body.error.code, "stale_case_revision");
    assert.equal(body.error.details.currentRevision, 7);
  });
});
