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

const directory = join(import.meta.dir, "..", "components");

test("all authentication components use theme tokens and Tailwind utilities", () => {
  const files = readdirSync(directory).filter((file) => file.endsWith(".wrn"));
  expect(files.length).toBeGreaterThanOrEqual(16);
  for (const file of files) {
    const source = readFileSync(join(directory, file), "utf8");
    expect(source).toContain("component ");
    expect(source).toContain("--wire-");
    expect(source).not.toContain("<style");
  }
});

test("passkey component declares the automatic package runtime", () => {
  const source = readFileSync(join(directory, "PasskeyButton.wrn"), "utf8");
  expect(source).toContain('data-wrnexus-runtime="auth"');
  expect(source).not.toContain("<script");
});

test("SignIn exposes a slot for CAPTCHA and application-specific controls", () => {
  const source = readFileSync(join(directory, "SignIn.wrn"), "utf8");
  expect(source).toContain("<slot></slot>");
  expect(source.indexOf("<slot></slot>")).toBeLessThan(source.indexOf('data-error="_form"'));
});

test("packaged auth forms use built-in schemas instead of native browser validation", () => {
  const files = readdirSync(directory).filter((file) => file.endsWith(".wrn"));
  for (const file of files) {
    const source = readFileSync(join(directory, file), "utf8");
    if (!source.includes("<form")) continue;
    expect(source).not.toContain(" required");
    for (const form of source.matchAll(/<form[\s\S]*?>/g)) {
      if (!form[0].includes("data-schema")) continue;
      expect(form[0]).toContain("novalidate");
    }
  }
});

test("passwordless and passkey components preserve MFA continuation metadata", () => {
  const otp = readFileSync(join(directory, "OtpSignIn.wrn"), "utf8");
  const passkey = readFileSync(join(directory, "PasskeyButton.wrn"), "utf8");
  const signIn = readFileSync(join(directory, "SignIn.wrn"), "utf8");
  expect(otp).toContain("data-mfa-href");
  expect(passkey).toContain("data-mfa-href");
  expect(signIn).toContain("mfaHref='{mfaHref}'");
  expect(signIn).toContain('name="deviceFingerprint"');
  expect(signIn).toContain('name="deviceName"');
});

test("recovery forms expose a form slot for CAPTCHA and policy controls", () => {
  const source = readFileSync(join(directory, "ForgotPassword.wrn"), "utf8");
  const formStart = source.indexOf("<form");
  const formEnd = source.indexOf("</form>");
  const slot = source.indexOf("<slot></slot>");

  expect(formStart).toBeGreaterThanOrEqual(0);
  expect(slot).toBeGreaterThan(formStart);
  expect(slot).toBeLessThan(formEnd);
});

test("account forms use the dedicated password components", () => {
  const signIn = readFileSync(join(directory, "SignIn.wrn"), "utf8");
  const signUp = readFileSync(join(directory, "SignUp.wrn"), "utf8");

  expect(signIn).toContain("<TogglePassword");
  expect(signIn).not.toContain('id="auth-sign-in-password"');
  expect(signUp).toContain("<StrongPassword");
  expect(signUp).not.toContain('id="auth-sign-up-password"');
});

test("authentication journeys use themed UI form controls", () => {
  const expected = {
    "SignIn.wrn": ["<Input", "<TogglePassword", "<Checkbox", "<Button"],
    "SignUp.wrn": ["<Input", "<StrongPassword", "<Checkbox", "<Button"],
    "ForgotPassword.wrn": ["<Input", "<Button"],
    "ResetPassword.wrn": ["<StrongPassword", "<Button"],
    "MagicLinkSignIn.wrn": ["<Input", "<Button"],
    "InvitationAccept.wrn": ["<Input", "<StrongPassword", "<Button"],
    "OtpSignIn.wrn": ["<Input", "<PinInput", "<Button"],
    "TwoFactorChallenge.wrn": ["<Select", "<PinInput", "<Button"],
    "AuthenticatorSetup.wrn": ["<Input", "<PinInput", "<Button"],
    "VerifyEmail.wrn": ["<Input", "<Button"],
    "VerifyPhone.wrn": ["<PinInput", "<Button"],
  };

  for (const [file, controls] of Object.entries(expected)) {
    const source = readFileSync(join(directory, file), "utf8");
    for (const control of controls) expect(source).toContain(control);
  }
});

test("verification components can resend without application-owned schema files", () => {
  const email = readFileSync(join(directory, "VerifyEmail.wrn"), "utf8");
  const phone = readFileSync(join(directory, "VerifyPhone.wrn"), "utf8");
  for (const source of [email, phone]) {
    expect(source).toContain('name="identifier"');
    expect(source).toContain("auth-verification-request");
    expect(source).toContain("novalidate");
  }
});

test("auth browser runtime refuses cross-origin navigation targets", () => {
  const source = readFileSync(join(directory, "..", "assets", "client", "auth.js"), "utf8");
  expect(source).toContain("if (url.origin !== location.origin) return false");
  expect(source).toContain("!window.AbortController");
});
