import { describe, expect, test } from "bun:test";
import { createContext } from "@wrnexus/core";
import { v } from "@wrnexus/validation";
import {
  captchaPlugin,
  defineCaptchaProvider,
  parseWithCaptcha,
  type CaptchaProvider,
} from "../src/index.ts";
import type { PluginContext, TransformContext } from "@wrnexus/plugin";

describe("CAPTCHA validation and development audit", () => {
  test("combines schema and action-bound provider verification failures", async () => {
    const requests: unknown[] = [];
    const provider: CaptchaProvider = defineCaptchaProvider({
      name: "fixture",
      client: { responseField: "captcha-response" },
      async verify(input) {
        requests.push(input);
        return { success: false, provider: "fixture", action: input.action, message: "Try again" };
      },
    });
    const ctx = createContext(
      new Request("https://app.test/signup"),
      new URL("https://app.test/signup"),
    );
    const result = await parseWithCaptcha(
      v.object({ email: v.string().email() }),
      { email: "invalid", "captcha-response": "token" },
      ctx,
      { action: "signup", provider, bindIp: true },
    );
    expect(result.ok).toBe(false);
    expect(result.errors.email).toBeDefined();
    expect(result.errors["captcha-response"]).toBe("Try again");
    expect(requests[0]).toEqual(
      expect.objectContaining({ action: "signup", hostname: "app.test", providerToken: "token" }),
    );
  });

  test("rejects incomplete custom providers", () => {
    expect(() =>
      defineCaptchaProvider({ name: "", client: { responseField: "x" } } as never),
    ).toThrow("stable name");
    expect(() =>
      defineCaptchaProvider({ name: "x", client: { responseField: "" } } as never),
    ).toThrow("responseField");
    expect(() =>
      defineCaptchaProvider({ name: "x", client: { responseField: "token" } } as never),
    ).toThrow("verify()");
  });

  test("flags exposed secrets, missing provider keys, and inaccessible hard challenges", async () => {
    const metadata = new Map<string, unknown>();
    const plugin = captchaPlugin();
    const context = {
      mode: "development",
      file: "signup.wrn",
      metadata,
    } as TransformContext;
    await plugin.transformCode?.(
      `<Captcha provider="turnstile" secretKey="leaked" action="signup" disturbance="90" showAudio="false" />`,
      context,
    );
    const panels = await plugin.devToolbarPanels?.({ metadata } as PluginContext);
    const ids = panels?.[0]?.issues?.map((issue) => String((issue as { id: string }).id)) ?? [];
    expect(ids.some((id) => id.startsWith("client-secret:"))).toBe(true);
    expect(ids.some((id) => id.startsWith("missing-site-key:"))).toBe(true);
    expect(ids.some((id) => id.startsWith("hard-without-audio:"))).toBe(true);
  });
});
