import { describe, expect, test } from "bun:test";
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";

const showcaseRoot = join(import.meta.dir, "..");
const repositoryRoot = join(showcaseRoot, "..", "..");
const packageComponentPath = join(
  repositoryRoot,
  "packages",
  "captcha",
  "components",
  "Captcha.wrn",
);

function path(relativePath: string): string {
  return join(showcaseRoot, relativePath);
}

function read(relativePath: string): string {
  return readFileSync(path(relativePath), "utf8");
}

describe("CAPTCHA showcase structure", () => {
  test("ships the required pages, routes, middleware, and component", () => {
    const requiredFiles = [
      "app/pages/index.wrn",
      "app/pages/captcha.wrn",
      "app/pages/protected.wrn",
      "app/pages/styles.wrn",
      "app/api/contact.ts",
      "app/api/page-grant.ts",
      "app/schemas/contact.ts",
      "app/lib/captcha.ts",
      "app/middleware/captcha-page-gate.ts",
      "app/styles/global.css",
      "wrnexus.config.ts",
    ];

    for (const relativePath of requiredFiles) {
      expect(existsSync(path(relativePath))).toBe(true);
    }
  });

  test("configures Tailwind and Lucide Iconify utilities", () => {
    const packageJson = read("package.json");
    const styles = read("app/styles/global.css");

    expect(packageJson).toContain('"@iconify-json/lucide"');
    expect(packageJson).toContain('"@iconify/tailwind4"');
    expect(styles).toContain('@plugin "@iconify/tailwind4";');
    expect(styles).not.toContain("packages/captcha/components");
    expect(read("wrnexus.config.ts")).not.toContain("includePackageSources: false");
  });

  test("documents every bundled challenge mode", () => {
    const source = read("app/pages/index.wrn");
    const expectedExamples = [
      'type="number"',
      'type="alpha"',
      'type="alphanumeric"',
      'type="calculation"',
      'type="image"',
      'type="timing"',
      'type="not-robot"',
      'presentation="audio"',
      'presentation="invisible"',
    ];

    for (const example of expectedExamples) {
      expect(source).toContain(example);
    }

    expect(source.match(/<Captcha\b/g)?.length ?? 0).toBeGreaterThanOrEqual(18);
    expect(source).toContain('disturbance="25"');
    expect(source).toContain('disturbance="50"');
    expect(source).toContain('disturbance="75"');
    expect(source).toContain('size="compact"');
    expect(source).toContain('size="normal"');
    expect(source).toContain('size="big"');
    expect(source).toContain('showListen="false"');
  });

  test("documents every generated image renderer and random pool controls", () => {
    const source = read("app/pages/styles.wrn");
    const styles = [
      "classic",
      "collision",
      "snow",
      "corrosion",
      "spiderweb",
      "cross-shadow",
      "split",
      "split2",
      "cut",
      "darts",
      "distortion",
      "stitch",
      "striped",
      "wave",
      "grid-noise",
      "scribble",
      "pixel",
      "broken-lines",
    ];

    for (const style of styles) {
      expect(source).toContain(`imageStyle="${style}"`);
    }

    expect(source).toContain('imageStyle="random"');
    expect(source).toContain('allowedStyles="classic,snow,distortion,wave"');
    expect(source).toContain('excludedStyles="collision,split,split2,broken-lines"');
    expect(source).toContain('difficulty="easy"');
    expect(source).toContain('difficulty="normal"');
    expect(source).toContain('difficulty="hard"');
    expect(source.match(/<Captcha\b/g)?.length ?? 0).toBeGreaterThanOrEqual(23);
  });

  test("includes protected form and external-provider examples", () => {
    const source = read("app/pages/index.wrn");

    expect(source).toContain('action="/api/contact"');
    expect(source).toContain('data-schema="contact"');
    expect(source).toContain('action="contact-submit"');
    expect(source).toContain('data-error="email"');
    expect(source).toContain('data-error="message"');
    expect(source).toContain('provider="turnstile"');
    expect(source).toContain('provider="recaptcha"');
    expect(source).toContain('provider="hcaptcha"');
  });
});

describe("CAPTCHA showcase integration", () => {
  test("configures the self-hosted engine and HTTP handlers", () => {
    const source = read("app/lib/captcha.ts");

    expect(source).toContain("createCaptchaEngine");
    expect(source).toContain("createCaptchaHttpHandlers");
    expect(source).toContain('basePath: "/api/captcha"');
    expect(source).toContain("challengeTtlMs: 2 * 60_000");
    expect(source).toContain("responseTokenTtlMs: 5 * 60_000");
    expect(source).toContain("maxAttempts: 3");
  });

  test("protects the contact form with a server-side guard", () => {
    const source = read("app/api/contact.ts");

    expect(source).toContain("captchaGuard");
    expect(source).toContain('action: "contact-submit"');
    expect(source).toContain('responseField: "wrn-captcha-response"');
    expect(source).toContain("bindHostname: true");
    expect(source).toContain("bindSession: true");
    expect(source).toContain("parseBody<ContactInput>");
    expect(source).toContain("contactSchema");
    expect(source).toContain("ctx.req.clone()");
  });

  test("protects the page route with a session grant", () => {
    const middleware = read("app/middleware/captcha-page-gate.ts");
    const challengePage = read("app/pages/captcha.wrn");

    expect(middleware).toContain("captchaPageGate");
    expect(middleware).toContain('action: "protected-page-access"');
    expect(middleware).toContain('mode: "session"');
    expect(middleware).toContain("verifiedForMs: 15 * 60_000");
    expect(middleware).toContain('routeGroups: ["/protected"]');
    expect(middleware).toContain('ctx.url.pathname === "/api/page-grant"');

    expect(challengePage).toContain('action="protected-page-access"');
    expect(challengePage).toContain('action="/api/page-grant"');
    expect(challengePage).toContain('name="returnTo"');
    expect(challengePage).toContain("value='{returnTo}'");

    const grantRoute = read("app/api/page-grant.ts");
    expect(grantRoute).toContain("safeReturnPath");
    expect(grantRoute).toContain('form.get("returnTo")');
    expect(grantRoute).toContain("Response.redirect");
  });

  test("auto-discovers the CAPTCHA package without manual plugin or script wiring", () => {
    const config = read("wrnexus.config.ts");
    const packageJson = read("package.json");
    const component = readFileSync(packageComponentPath, "utf8");

    expect(packageJson).toContain('"@wrnexus/captcha": "workspace:*"');
    expect(existsSync(path("app/components/Captcha.wrn"))).toBe(false);
    expect(existsSync(packageComponentPath)).toBe(true);
    expect(config).not.toContain("captchaPlugin");
    expect(config).not.toContain("plugins:");
    expect(component).toContain('data-wrnexus-runtime="captcha"');
    expect(component).not.toContain("<script");
    expect(component).not.toContain("captcha.js");
  });

  test("ships the expected component events and response field", () => {
    const source = readFileSync(packageComponentPath, "utf8");
    const expectedEvents = [
      "ready",
      "challenge",
      "input",
      "verify",
      "success",
      "failure",
      "expired",
      "refresh",
      "audioStart",
      "audioEnd",
      "error",
    ];

    expect(source).toContain('name = "wrn-captcha-response"');
    expect(source).toContain('responseField = "wrn-captcha-response"');
    expect(source).toContain("disturbance = 50");
    expect(source).toContain('size = "normal"');
    expect(source).toContain("showListen = true");
    expect(source).toContain('imageStyle = "random"');
    expect(source).toContain('allowedStyles = ""');
    expect(source).toContain('excludedStyles = ""');
    expect(source).toContain("randomizeStyle = false");
    expect(source).toContain("data-captcha-not-robot-button");

    for (const eventName of expectedEvents) {
      expect(source).toContain(`@event ${eventName} = function`);
    }
  });
});
