import { describe, expect, test } from "bun:test";
import { createAuthEngine } from "../src/engine.ts";
import { MemoryAuthStore } from "../src/stores/memory.ts";
import { generateTotp } from "../src/totp/index.ts";
import type { AuthDeliveryMessage, PasskeyProvider } from "../src/types.ts";

function fixture() {
  let time = 1_720_000_000_000;
  let seed = 11;
  const messages: AuthDeliveryMessage[] = [];
  const engine = createAuthEngine({
    store: new MemoryAuthStore(),
    secret: "test-auth-secret-that-is-longer-than-thirty-two-characters",
    issuer: "WRNexus Test",
    clock: { now: () => time },
    random: {
      bytes(length) {
        const bytes = new Uint8Array(length);
        for (let index = 0; index < length; index += 1) {
          seed = (seed * 1664525 + 1013904223) >>> 0;
          bytes[index] = seed & 255;
        }
        return bytes;
      },
    },
    delivery: {
      async send(message) {
        messages.push(message);
      },
    },
  });
  return {
    engine,
    messages,
    advance(ms: number) {
      time += ms;
    },
    now: () => time,
  };
}

describe("authentication engine", () => {
  test("rejects unsafe numeric authentication configuration", () => {
    expect(() =>
      createAuthEngine({
        store: new MemoryAuthStore(),
        secret: "invalid-config-secret-that-is-longer-than-thirty-two-characters",
        sessionTtlMs: Number.NaN,
      }),
    ).toThrow("sessionTtlMs");
    expect(() =>
      createAuthEngine({
        store: new MemoryAuthStore(),
        secret: "invalid-config-secret-that-is-longer-than-thirty-two-characters",
        passwordMinLength: 4,
      }),
    ).toThrow("passwordMinLength");
  });

  test("registers, verifies email, signs in, and validates the session", async () => {
    const { engine, messages } = fixture();
    const registered = await engine.register({
      email: "Owner@Example.com",
      username: "owner",
      displayName: "Owner",
      password: "StrongPassword123",
    });
    expect(registered.ok).toBe(true);
    expect(messages[0]?.template).toBe("verify-email");
    const verified = await engine.verifyEmail(messages[0]!.token!);
    expect(verified).toMatchObject({ ok: true, user: { emailVerified: true } });

    const login = await engine.login({
      identifier: "owner@example.com",
      password: "StrongPassword123",
    });
    expect(login.ok).toBe(true);
    expect(login.session).toBeDefined();
    expect(await engine.validateSession(login.session!.id)).toMatchObject({
      userId: registered.user!.id,
    });
  });

  test("delivery provider failures do not corrupt completed authentication state", async () => {
    const store = new MemoryAuthStore();
    const engine = createAuthEngine({
      store,
      secret: "delivery-failure-secret-that-is-longer-than-thirty-two-characters",
      sendLoginAlerts: true,
      delivery: {
        async send() {
          throw new Error("provider unavailable");
        },
      },
    });

    const registered = await engine.register({
      email: "delivery-failure@example.com",
      password: "StrongPassword123",
    });
    expect(registered.ok).toBe(true);
    const user = await store.findUserById(registered.user!.id);
    user!.status = "active";
    user!.emailVerified = true;
    await store.updateUser(user!);

    const login = await engine.login({
      identifier: "delivery-failure@example.com",
      password: "StrongPassword123",
    });
    expect(login.ok).toBe(true);
    expect(
      (await store.listSecurityEvents(registered.user!.id)).some(
        (event) => event.type === "delivery.failed",
      ),
    ).toBe(true);
  });

  test("engine-level registration rejects malformed identities before persistence", async () => {
    const { engine } = fixture();
    expect(
      await engine.register({ email: "not-an-email", password: "StrongPassword123" }),
    ).toMatchObject({ ok: false, code: "registration-failed" });
    expect(await engine.register({ phone: "+12", password: "StrongPassword123" })).toMatchObject({
      ok: false,
      code: "registration-failed",
    });
    expect(await engine.store.listUsers()).toHaveLength(0);
  });

  test("normalizes identities and rejects duplicates", async () => {
    const { engine } = fixture();
    expect(
      (await engine.register({ email: "One@Example.com", password: "StrongPassword123" })).ok,
    ).toBe(true);
    const duplicate = await engine.register({
      email: "one@example.com",
      password: "AnotherStrong123",
    });
    expect(duplicate).toMatchObject({ ok: false, code: "registration-failed" });
  });

  test("issues and consumes password reset links once", async () => {
    const { engine, messages } = fixture();
    await engine.register({ email: "reset@example.com", password: "StrongPassword123" });
    await engine.requestPasswordReset("reset@example.com", "https://example.test");
    const token = messages.find((message) => message.template === "password-reset")!.token!;
    expect((await engine.resetPassword(token, "NewStrongPassword456")).ok).toBe(true);
    expect((await engine.resetPassword(token, "OtherStrongPassword789")).ok).toBe(false);
    expect(
      (await engine.login({ identifier: "reset@example.com", password: "NewStrongPassword456" }))
        .ok,
    ).toBe(true);
  });

  test("supports email OTP verification with attempt and expiry protection", async () => {
    const { engine, messages, advance } = fixture();
    const registered = await engine.register({
      email: "otp@example.com",
      password: "StrongPassword123",
    });
    const challenge = await engine.issueOtp(registered.user!.id, "email-otp");
    const code = messages.find((message) => message.template === "email-otp")!.code!;
    expect((await engine.verifyOtp(challenge.id, "000000")).ok).toBe(false);
    expect((await engine.verifyOtp(challenge.id, `${code.slice(0, 3)}-${code.slice(3)}`)).ok).toBe(
      false,
    );
    expect((await engine.verifyOtp(challenge.id, code)).ok).toBe(true);
    expect((await engine.verifyOtp(challenge.id, code)).ok).toBe(false);

    const expired = await engine.issueOtp(registered.user!.id, "email-otp");
    advance(11 * 60_000);
    expect((await engine.verifyOtp(expired.id, messages.at(-1)!.code!)).ok).toBe(false);
  });

  test("binds OTPs to linked destinations and to their intended flow", async () => {
    const { engine, messages } = fixture();
    const registered = await engine.register({
      email: "bound@example.com",
      password: "StrongPassword123",
    });

    let rejected = false;
    try {
      await engine.issueOtp(registered.user!.id, "email-otp", "attacker@example.com");
    } catch {
      rejected = true;
    }
    expect(rejected).toBe(true);

    const loginChallenge = await engine.requestOtpLogin("bound@example.com", "email-otp");
    const code = messages.find((message) => message.template === "email-otp")!.code!;
    expect((await engine.verifyOtp(loginChallenge!.id, code)).ok).toBe(false);
    expect((await engine.completeOtpLogin(loginChallenge!.id, code)).ok).toBe(true);
  });

  test("returns an opaque OTP challenge for an unknown account", async () => {
    const { engine, messages } = fixture();
    const challenge = await engine.requestOtpLogin("missing@example.com", "email-otp");
    expect(challenge?.id.startsWith("otp_")).toBe(true);
    expect(messages).toHaveLength(0);
    expect((await engine.completeOtpLogin(challenge!.id, "123456")).ok).toBe(false);
  });

  test("enables replay-safe TOTP and one-use recovery codes", async () => {
    const { engine, now } = fixture();
    const registered = await engine.register({
      email: "mfa@example.com",
      password: "StrongPassword123",
    });
    const setup = await engine.beginTotp(registered.user!.id, "Primary authenticator");
    const token = await generateTotp(setup.secret, { timestamp: now() });
    expect(await engine.confirmTotp(registered.user!.id, setup.credentialId, token)).toBe(true);
    const next = await generateTotp(setup.secret, { timestamp: now() + 30_000 });
    expect(await engine.verifyTotp(registered.user!.id, next)).toBe(true);
    expect(await engine.verifyTotp(registered.user!.id, next)).toBe(false);

    const codes = await engine.generateRecoveryCodes(registered.user!.id, 3);
    expect(codes).toHaveLength(3);
    expect(await engine.consumeRecoveryCode(registered.user!.id, codes[0]!)).toBe(true);
    expect(await engine.consumeRecoveryCode(registered.user!.id, codes[0]!)).toBe(false);
    expect(await engine.listRecoveryCodeStatus(registered.user!.id)).toEqual({
      total: 3,
      remaining: 2,
    });

    const replacement = await engine.generateRecoveryCodes(registered.user!.id, 2);
    expect(await engine.consumeRecoveryCode(registered.user!.id, codes[1]!)).toBe(false);
    expect(await engine.consumeRecoveryCode(registered.user!.id, replacement[0]!)).toBe(true);
  });

  test("creates a trusted session when remember-device is requested", async () => {
    const { engine } = fixture();
    await engine.register({ email: "remember@example.com", password: "StrongPassword123" });
    const result = await engine.login({
      identifier: "remember@example.com",
      password: "StrongPassword123",
      fingerprint: "browser-fingerprint",
      deviceName: "Work browser",
      rememberDevice: true,
    });
    expect(result).toMatchObject({ ok: true, session: { trusted: true } });
  });

  test("tracks and revokes sessions and trusted devices", async () => {
    const { engine } = fixture();
    const registered = await engine.register({
      email: "devices@example.com",
      password: "StrongPassword123",
    });
    const device = await engine.trustDevice(registered.user!.id, {
      fingerprint: "browser-device",
      name: "Work laptop",
    });
    expect(device.name).toBe("Work laptop");
    const session = await engine.createSession(registered.user!.id, {
      fingerprint: "browser-device",
    });
    expect(session.trusted).toBe(true);
    expect(await engine.revokeSession(registered.user!.id, session.id)).toBe(true);
    expect(await engine.validateSession(session.id)).toBeUndefined();
  });

  test("lists only active sessions and removes expired records", async () => {
    const { engine, advance } = fixture();
    const registered = await engine.register({
      email: "active-sessions@example.com",
      password: "StrongPassword123",
    });
    const expired = await engine.createSession(registered.user!.id);
    advance(25 * 60 * 60_000);
    const active = await engine.createSession(registered.user!.id);

    expect(await engine.listSessions(registered.user!.id)).toEqual([active]);
    expect(await engine.store.findSession(expired.id)).toBeUndefined();
  });

  test("does not reveal account status before password verification", async () => {
    const { engine } = fixture();
    const registered = await engine.register({
      email: "disabled-login@example.com",
      password: "StrongPassword123",
    });
    await engine.setAccountStatus(registered.user!.id, "disabled");

    const wrongPassword = await engine.login({
      identifier: "disabled-login@example.com",
      password: "WrongPassword999",
    });
    const unknownAccount = await engine.login({
      identifier: "missing-login@example.com",
      password: "WrongPassword999",
    });
    expect(wrongPassword).toMatchObject({
      ok: false,
      code: "invalid-credentials",
      message: "The email, phone, username, or password you entered is incorrect.",
    });
    expect(unknownAccount).toMatchObject({
      ok: false,
      code: "invalid-credentials",
      message: wrongPassword.message,
    });
    expect(
      await engine.login({
        identifier: "disabled-login@example.com",
        password: "StrongPassword123",
      }),
    ).toMatchObject({
      ok: false,
      code: "account-disabled",
      message: "This account is disabled. Contact support for help.",
    });
  });

  test("raises CAPTCHA and blocks repeated suspicious sign-in attempts", async () => {
    const { engine } = fixture();
    await engine.register({ email: "risk@example.com", password: "StrongPassword123" });
    for (let index = 0; index < 4; index += 1) {
      await engine.login({
        identifier: "risk@example.com",
        password: "WrongPassword999",
        captchaVerified: true,
      });
    }
    const captcha = await engine.login({
      identifier: "risk@example.com",
      password: "WrongPassword999",
    });
    expect(captcha).toMatchObject({
      ok: false,
      code: "captcha-required",
      requires: { captcha: true },
    });

    await engine.login({
      identifier: "risk@example.com",
      password: "WrongPassword999",
      captchaVerified: true,
    });
    const blocked = await engine.login({
      identifier: "risk@example.com",
      password: "WrongPassword999",
      captchaVerified: true,
    });
    expect(blocked.ok).toBe(false);
    expect(blocked.risk?.block).toBe(true);
  });

  test("links OAuth accounts and creates users for new provider identities", async () => {
    const { engine } = fixture();
    const result = await engine.loginWithOAuth(" GitHub ", {
      id: "github-123",
      email: "oauth@example.com",
      name: "OAuth User",
      raw: { email_verified: true },
    });
    expect(result.ok).toBe(true);
    expect(result.user?.emailVerified).toBe(true);
    const accounts = await engine.store.listOAuthAccounts(result.user!.id);
    expect(accounts).toHaveLength(1);
    expect(accounts[0]?.provider).toBe("github");
  });

  test("creates and accepts a single-use invitation", async () => {
    const { engine, messages } = fixture();
    const invitation = await engine.createInvitation({
      email: "invited@example.com",
      displayName: "Invited User",
      roles: ["member"],
      invitedBy: "admin-user",
      baseUrl: "https://example.test",
    });
    expect(messages.at(-1)?.template).toBe("invitation");
    const accepted = await engine.acceptInvitation(invitation.token, {
      password: "StrongPassword123",
    });
    expect(accepted).toMatchObject({ ok: true, user: { emailVerified: true, status: "active" } });
    expect(accepted.user?.roles).toContain("member");
    expect(
      (await engine.acceptInvitation(invitation.token, { password: "StrongPassword123" })).ok,
    ).toBe(false);
  });

  test("customizes delivered token links without application-owned auth APIs", async () => {
    const messages: AuthDeliveryMessage[] = [];
    const engine = createAuthEngine({
      store: new MemoryAuthStore(),
      secret: "token-url-test-secret-that-is-longer-than-thirty-two-characters",
      delivery: {
        async send(message) {
          messages.push(message);
        },
      },
      tokenUrl({ purpose, token, baseUrl }) {
        if (!baseUrl) return undefined;
        const path =
          purpose === "password-reset"
            ? `/recover/reset?token=${encodeURIComponent(token)}`
            : purpose === "invite"
              ? `/invitation?token=${encodeURIComponent(token)}`
              : `/${purpose}?token=${encodeURIComponent(token)}`;
        return new URL(path, baseUrl).toString();
      },
    });

    await engine.register({
      email: "links@example.com",
      password: "StrongPassword123",
    });
    messages.length = 0;

    await engine.requestPasswordReset("links@example.com", "https://example.test");
    expect(messages.at(-1)?.url?.startsWith("https://example.test/recover/reset?token=")).toBe(
      true,
    );

    await engine.createInvitation({
      email: "invited-links@example.com",
      baseUrl: "https://example.test",
    });
    expect(messages.at(-1)?.url?.startsWith("https://example.test/invitation?token=")).toBe(true);
  });

  test("supports passwordless OTP login and sends a login alert", async () => {
    const { engine, messages } = fixture();
    await engine.register({ email: "passwordless@example.com", password: "StrongPassword123" });
    const challenge = await engine.requestOtpLogin("passwordless@example.com", "email-otp");
    const code = messages.find((message) => message.template === "email-otp")!.code!;
    const result = await engine.completeOtpLogin(challenge!.id, code);
    expect(result).toMatchObject({ ok: true, user: { emailVerified: true } });
    expect(result.session).toBeDefined();
  });

  test("protects TOTP and OAuth secrets before persistence", async () => {
    const store = new MemoryAuthStore();
    const protectedValues: string[] = [];
    const engine = createAuthEngine({
      store,
      secret: "protector-test-secret-that-is-longer-than-thirty-two-characters",
      secretProtector: {
        async protect(value, purpose) {
          const output = `sealed:${purpose}:${value}`;
          protectedValues.push(output);
          return output;
        },
        async reveal(value) {
          return value.split(":").slice(2).join(":");
        },
      },
    });
    const registered = await engine.register({
      email: "protected@example.com",
      password: "StrongPassword123",
    });
    const setup = await engine.beginTotp(registered.user!.id);
    expect((await store.listTotp(registered.user!.id))[0]?.secret.startsWith("sealed:totp:")).toBe(
      true,
    );
    await engine.linkOAuth(
      registered.user!.id,
      "example",
      { id: "provider-id", raw: {} },
      {
        access_token: "access",
        refresh_token: "refresh",
        token_type: "Bearer",
      },
    );
    expect(protectedValues.some((value) => value.startsWith("sealed:oauth-access:"))).toBe(true);
    expect(setup.secret.startsWith("sealed:")).toBe(false);
  });

  test("requires an explicit policy and audits impersonation sessions", async () => {
    const store = new MemoryAuthStore();
    const engine = createAuthEngine({
      store,
      secret: "impersonation-secret-that-is-longer-than-thirty-two-characters",
      authorizeImpersonation: ({ actor }) => actor.roles.includes("admin"),
    });
    const actorResult = await engine.register({
      email: "admin@example.com",
      password: "StrongPassword123",
    });
    const targetResult = await engine.register({
      email: "target@example.com",
      password: "StrongPassword123",
    });
    const actor = await store.findUserById(actorResult.user!.id);
    const target = await store.findUserById(targetResult.user!.id);
    actor!.roles = ["admin"];
    actor!.status = "active";
    target!.status = "active";
    await store.updateUser(actor!);
    await store.updateUser(target!);
    const actorSession = await engine.createSession(actor!.id);
    const started = await engine.startImpersonation(actor!.id, target!.id, {
      sessionId: actorSession.id,
      reason: "Support case",
    });
    expect(started).toMatchObject({ ok: true, user: { id: target!.id } });
    expect(started.session?.metadata).toMatchObject({ impersonated: true, actorUserId: actor!.id });
    const stopped = await engine.stopImpersonation(started.session!.id);
    expect(stopped).toMatchObject({
      ok: true,
      user: { id: actor!.id },
      session: { id: actorSession.id },
    });
  });

  test("does not auto-link an unverified OAuth email to an existing account", async () => {
    const { engine } = fixture();
    await engine.register({ email: "existing@example.com", password: "StrongPassword123" });
    const result = await engine.loginWithOAuth("unknown", {
      id: "provider-unverified",
      email: "existing@example.com",
      raw: { email_verified: false },
    });
    expect(result).toMatchObject({ ok: false, code: "oauth-link-required" });
  });

  test("uses a configured passkey provider for registration and authentication", async () => {
    let expectedOrigin = "";
    let expectedRpId = "";
    const provider: PasskeyProvider = {
      async registrationOptions() {
        return {
          challenge: "AQID",
          rp: { id: "example.test", name: "Test" },
          user: { id: "AQID", name: "user", displayName: "User" },
          timeout: 1,
          attestation: "none",
        };
      },
      async verifyRegistration() {
        return {
          verified: true,
          credential: {
            credentialId: "cred-1",
            publicKey: "public",
            counter: 0,
            transports: ["internal"],
            name: "Device passkey",
          },
        };
      },
      async authenticationOptions() {
        return {
          challenge: "BAUG",
          rpId: "example.test",
          timeout: Number.POSITIVE_INFINITY,
          userVerification: "preferred",
        };
      },
      async verifyAuthentication(input) {
        expectedOrigin = input.expectedOrigin;
        expectedRpId = input.expectedRpId;
        return { verified: true, credentialId: "cred-1", newCounter: 1 };
      },
    };
    let time = 1_720_000_000_000;
    const engine = createAuthEngine({
      store: new MemoryAuthStore(),
      secret: "passkey-test-secret-that-is-longer-than-thirty-two-characters",
      passkeys: provider,
      clock: { now: () => time },
    });
    const registered = await engine.register({
      email: "passkey@example.com",
      password: "StrongPassword123",
    });
    const start = await engine.beginPasskeyRegistration(registered.user!.id, {
      rpId: "example.test",
      rpName: "Test",
      origin: "https://example.test",
    });
    expect(start.options.timeout).toBe(30_000);
    expect(
      await engine.finishPasskeyRegistration(registered.user!.id, {
        key: start.key,
        response: {},
        rpId: "example.test",
        origin: "https://example.test",
      }),
    ).toBe(true);
    const auth = await engine.beginPasskeyAuthentication({
      identifier: "passkey@example.com",
      rpId: "example.test",
      origin: "https://example.test",
    });
    expect(auth.options.timeout).toBe(5 * 60_000);
    time += 1;
    expect(
      (
        await engine.finishPasskeyAuthentication({
          key: auth.key,
          response: { id: "cred-1" },
          rpId: "example.test",
          origin: "https://example.test",
        })
      ).ok,
    ).toBe(true);
    expect(expectedOrigin).toBe("https://example.test");
    expect(expectedRpId).toBe("example.test");

    const repeatedCounter = await engine.beginPasskeyAuthentication({
      identifier: "passkey@example.com",
      rpId: "example.test",
      origin: "https://example.test",
    });
    expect(
      await engine.finishPasskeyAuthentication({
        key: repeatedCounter.key,
        response: { id: "cred-1" },
      }),
    ).toMatchObject({ ok: false, code: "passkey-counter-regression" });

    await engine.setAccountStatus(registered.user!.id, "disabled");
    const disabledAuth = await engine.beginPasskeyAuthentication({
      identifier: "passkey@example.com",
      rpId: "example.test",
      origin: "https://example.test",
    });
    expect(
      await engine.finishPasskeyAuthentication({
        key: disabledAuth.key,
        response: { id: "cred-1" },
      }),
    ).toMatchObject({ ok: false, code: "account-disabled" });
  });

  test("rejects a passkey result that switches away from the identified user", async () => {
    const store = new MemoryAuthStore();
    const provider: PasskeyProvider = {
      async registrationOptions() {
        throw new Error("not used");
      },
      async verifyRegistration() {
        return { verified: false };
      },
      async authenticationOptions() {
        return {
          challenge: "BAUG",
          rpId: "example.test",
          timeout: 60_000,
          userVerification: "required",
        };
      },
      async verifyAuthentication() {
        return { verified: true, userId: "different-user" };
      },
    };
    const engine = createAuthEngine({
      store,
      secret: "passkey-switch-secret-that-is-longer-than-thirty-two-characters",
      passkeys: provider,
    });
    const registered = await engine.register({
      email: "identified@example.com",
      password: "StrongPassword123",
    });
    const auth = await engine.beginPasskeyAuthentication({
      identifier: "identified@example.com",
      rpId: "example.test",
      origin: "https://example.test",
    });
    const result = await engine.finishPasskeyAuthentication({ key: auth.key, response: {} });
    expect(result).toMatchObject({ ok: false, code: "passkey-user-mismatch" });
    expect(registered.user?.id).toBeDefined();
  });

  test("passwordless flows respect account status and enrolled MFA", async () => {
    const { engine, messages, now } = fixture();
    const registered = await engine.register({
      email: "passwordless-mfa@example.com",
      password: "StrongPassword123",
    });
    const setup = await engine.beginTotp(registered.user!.id);
    const token = await generateTotp(setup.secret, { timestamp: now() });
    expect(await engine.confirmTotp(registered.user!.id, setup.credentialId, token)).toBe(true);

    await engine.requestMagicLink("passwordless-mfa@example.com", "https://example.test");
    const magicToken = messages.find((message) => message.template === "magic-link")!.token!;
    expect(await engine.consumeMagicLink(magicToken)).toMatchObject({
      ok: false,
      code: "mfa-required",
      requires: { mfa: expect.any(Array) },
    });

    const otp = await engine.requestOtpLogin("passwordless-mfa@example.com", "email-otp");
    const otpCode = messages.filter((message) => message.template === "email-otp").at(-1)!.code!;
    expect(await engine.completeOtpLogin(otp.id, otpCode)).toMatchObject({
      ok: false,
      code: "mfa-required",
    });

    await engine.setAccountStatus(registered.user!.id, "disabled");
    const second = await engine.requestOtpLogin("passwordless-mfa@example.com", "email-otp");
    expect(await engine.completeOtpLogin(second.id, "000000")).toMatchObject({
      ok: false,
      code: "invalid-otp",
    });
  });

  test("temporary login locks do not activate a pending account when they expire", async () => {
    let time = 1_720_000_000_000;
    const store = new MemoryAuthStore();
    const engine = createAuthEngine({
      store,
      secret: "pending-lock-secret-that-is-longer-than-thirty-two-characters",
      requireVerifiedEmail: true,
      maxFailedLogins: 1,
      lockDurationMs: 60_000,
      clock: { now: () => time },
    });
    const registered = await engine.register({
      email: "pending-lock@example.com",
      password: "StrongPassword123",
    });
    await engine.login({
      identifier: "PENDING-LOCK@example.com",
      password: "WrongPassword999",
      captchaVerified: true,
    });
    expect((await store.findUserById(registered.user!.id))?.status).toBe("locked");
    time += 61_000;
    const login = await engine.login({
      identifier: "pending-lock@example.com",
      password: "StrongPassword123",
      captchaVerified: true,
    });
    expect(login).toMatchObject({ ok: false, code: "email-unverified" });
    expect((await store.findUserById(registered.user!.id))?.status).toBe("pending");
  });

  test("OAuth refreshes preserve stored tokens when a provider omits them", async () => {
    const { engine } = fixture();
    const registered = await engine.register({
      email: "oauth-refresh@example.com",
      password: "StrongPassword123",
    });
    const profile = { id: "oauth-refresh-id", email: "oauth-refresh@example.com", raw: {} };
    const first = await engine.linkOAuth(registered.user!.id, "example", profile, {
      access_token: "access-token",
      refresh_token: "refresh-token",
      token_type: "Bearer",
      scope: "openid profile",
    });
    const second = await engine.linkOAuth(registered.user!.id, "example", profile);
    expect(second.accessToken).toBe(first.accessToken);
    expect(second.refreshToken).toBe(first.refreshToken);
    expect(second.scope).toBe(first.scope);
  });

  test("disabled accounts cannot use previously issued recovery or verification tokens", async () => {
    const { engine, messages } = fixture();
    const registered = await engine.register({
      email: "disabled-recovery@example.com",
      password: "StrongPassword123",
    });
    const verificationToken = messages.find(
      (message) => message.template === "verify-email",
    )!.token!;
    await engine.requestPasswordReset("disabled-recovery@example.com", "https://example.test");
    const resetToken = messages.find((message) => message.template === "password-reset")!.token!;

    await engine.setAccountStatus(registered.user!.id, "disabled");
    expect(await engine.verifyEmail(verificationToken)).toMatchObject({
      ok: false,
      code: "account-disabled",
    });
    expect(await engine.resetPassword(resetToken, "ReplacementPassword456")).toMatchObject({
      ok: false,
      code: "account-disabled",
    });
    const before = messages.length;
    await engine.requestPasswordReset("disabled-recovery@example.com", "https://example.test");
    expect(messages).toHaveLength(before);

    // Administrative re-enablement leaves the original one-time credentials
    // available because the disabled-account checks did not consume them.
    await engine.setAccountStatus(registered.user!.id, "active");
    expect((await engine.verifyEmail(verificationToken)).ok).toBe(true);
    expect((await engine.resetPassword(resetToken, "ReplacementPassword456")).ok).toBe(true);
  });

  test("a valid password reset clears a failed-login lock without activating pending users", async () => {
    const store = new MemoryAuthStore();
    const messages: AuthDeliveryMessage[] = [];
    const engine = createAuthEngine({
      store,
      secret: "password-reset-lock-secret-that-is-longer-than-thirty-two-characters",
      maxFailedLogins: 1,
      delivery: {
        async send(message) {
          messages.push(message);
        },
      },
    });
    const registered = await engine.register({
      email: "locked-reset@example.com",
      password: "StrongPassword123",
    });
    await engine.login({
      identifier: "locked-reset@example.com",
      password: "WrongPassword123",
      captchaVerified: true,
    });
    expect((await store.findUserById(registered.user!.id))?.status).toBe("locked");

    await engine.requestPasswordReset("locked-reset@example.com", "https://example.test");
    const token = messages
      .filter((message) => message.template === "password-reset")
      .at(-1)!.token!;
    expect((await engine.resetPassword(token, "ReplacementPassword456")).ok).toBe(true);
    expect((await store.findUserById(registered.user!.id))?.status).toBe("pending");
    expect(
      (
        await engine.login({
          identifier: "locked-reset@example.com",
          password: "ReplacementPassword456",
          captchaVerified: true,
        })
      ).ok,
    ).toBe(true);
  });

  test("MFA email and SMS challenges require verified linked identities", async () => {
    const { engine, messages, now } = fixture();
    const registered = await engine.register({
      email: "unverified-mfa@example.com",
      password: "StrongPassword123",
    });
    const verificationToken = messages.find(
      (message) => message.template === "verify-email",
    )!.token!;
    const setup = await engine.beginTotp(registered.user!.id);
    const token = await generateTotp(setup.secret, { timestamp: now() });
    expect(await engine.confirmTotp(registered.user!.id, setup.credentialId, token)).toBe(true);

    const firstLogin = await engine.login({
      identifier: "unverified-mfa@example.com",
      password: "StrongPassword123",
    });
    expect(firstLogin).toMatchObject({
      ok: false,
      code: "mfa-required",
      requires: { mfa: ["totp"] },
    });
    expect(await engine.beginMfaOtp(firstLogin.mfaToken!, "email-otp")).toBeUndefined();

    expect((await engine.verifyEmail(verificationToken)).ok).toBe(true);
    const secondLogin = await engine.login({
      identifier: "unverified-mfa@example.com",
      password: "StrongPassword123",
    });
    expect(secondLogin.requires?.mfa).toContain("email-otp");
    expect(secondLogin.requires?.mfa).toContain("totp");
    expect(await engine.beginMfaOtp(secondLogin.mfaToken!, "email-otp")).toBeDefined();
  });
});
