import { describe, expect, test } from "bun:test";
import {
  createCaptchaEngine,
  MemoryCaptchaStore,
  type CaptchaChallengeGenerator,
} from "@wrnexus/captcha/server";
import { ManagedCaptchaService } from "../src/service.ts";

let seed = 11;
function randomBytes(length: number): Uint8Array {
  const output = new Uint8Array(length);
  for (let index = 0; index < length; index += 1) {
    seed = (seed * 1103515245 + 12345) >>> 0;
    output[index] = seed & 255;
  }
  return output;
}

const generator: CaptchaChallengeGenerator = {
  type: "number",
  generate: () => ({
    type: "number",
    presentation: "visual",
    prompt: "Enter 7",
    answer: "7",
    answerKind: "text",
    inputMode: "numeric",
  }),
};

describe("managed CAPTCHA service", () => {
  test("creates a project and completes the public-to-server flow", async () => {
    const service = new ManagedCaptchaService({
      adminToken: "a-long-admin-token-for-managed-captcha-tests",
      baseUrl: "https://captcha.test",
      randomBytes,
      engineFactory: (project) =>
        createCaptchaEngine({
          secret: project.engineSecret,
          store: new MemoryCaptchaStore(),
          generators: [generator],
          defaultType: "number",
          minCompletionMs: 0,
          randomBytes,
        }),
    });
    const project = await service.createProject({ name: "Test", allowedHostnames: ["app.test"] });
    const created = await service.handle(
      new Request("https://captcha.test/v1/challenges", {
        method: "POST",
        headers: { origin: "https://app.test", "content-type": "application/json" },
        body: JSON.stringify({ siteKey: project.siteKey, action: "signup", type: "number" }),
      }),
    );
    expect(created.status).toBe(201);
    const challenge = (await created.json()) as { id: string; provider: string };
    expect(challenge.provider).toBe("wrnexus-managed");

    const solved = await service.handle(
      new Request("https://captcha.test/v1/solve", {
        method: "POST",
        headers: { origin: "https://app.test", "content-type": "application/json" },
        body: JSON.stringify({ challengeId: challenge.id, action: "signup", answer: "7" }),
      }),
    );
    expect(solved.status).toBe(200);
    const solution = (await solved.json()) as { responseToken: string };

    const verified = await service.handle(
      new Request("https://captcha.test/v1/verify", {
        method: "POST",
        headers: {
          authorization: `Bearer ${project.secretKey}`,
          "content-type": "application/json",
        },
        body: JSON.stringify({
          responseToken: solution.responseToken,
          action: "signup",
          hostname: "app.test",
        }),
      }),
    );
    expect(verified.status).toBe(200);

    const replay = await service.handle(
      new Request("https://captcha.test/v1/verify", {
        method: "POST",
        headers: {
          authorization: `Bearer ${project.secretKey}`,
          "content-type": "application/json",
        },
        body: JSON.stringify({
          responseToken: solution.responseToken,
          action: "signup",
          hostname: "app.test",
        }),
      }),
    );
    expect(replay.status).toBe(400);
  });
});
