/**
 * Unit tests for the MFA error classes exported from auth.ts.
 *
 * These tests are a regression guard: they verify that the three
 * CredentialsSignin subclasses carry the correct `code` value so that
 * Auth.js v5 forwards them to the client via SignInResponse.code instead of
 * wrapping them as a generic CallbackRouteError.
 *
 * Testing the full authorize() call graph requires mocking the entire Next.js
 * runtime and is covered by E2E tests instead.
 */

import { describe, expect, it, vi } from "vitest";

// ── next-auth imports next/server without .js extension which fails in vitest
// node env. Mock the whole module so the error classes can be imported.
vi.mock("next-auth", () => {
  class CredentialsSignin extends Error {
    code = "credentials";
  }
  return {
    default: vi.fn().mockReturnValue({ handlers: {}, auth: vi.fn() }),
    CredentialsSignin,
  };
});

// ── All other side-effectful imports auth.ts pulls in ───────────────────────
vi.mock("./runtime-env.js", () => ({ assertSecureRuntimeEnv: vi.fn() }));
vi.mock("next-auth/providers/credentials", () => ({ default: vi.fn() }));
vi.mock("@capakraken/db", () => ({
  prisma: { user: {}, systemSettings: {}, activeSession: {} },
}));
vi.mock("@capakraken/api/middleware/rate-limit", () => ({ authRateLimiter: vi.fn() }));
vi.mock("@capakraken/api/lib/audit", () => ({ createAuditEntry: vi.fn() }));
vi.mock("@capakraken/api/lib/logger", () => ({
  logger: { warn: vi.fn(), error: vi.fn(), info: vi.fn() },
}));
vi.mock("@node-rs/argon2", () => ({ verify: vi.fn() }));

// ── Import the exported error classes after mocks are in place ───────────────
const { MfaRequiredError, MfaRequiredSetupError, InvalidTotpError } = await import("./auth.js");

describe("MFA CredentialsSignin error classes — code property", () => {
  it("MfaRequiredError.code is 'MFA_REQUIRED'", () => {
    expect(new MfaRequiredError().code).toBe("MFA_REQUIRED");
  });

  it("MfaRequiredSetupError.code is 'MFA_REQUIRED_SETUP'", () => {
    expect(new MfaRequiredSetupError().code).toBe("MFA_REQUIRED_SETUP");
  });

  it("InvalidTotpError.code is 'INVALID_TOTP'", () => {
    expect(new InvalidTotpError().code).toBe("INVALID_TOTP");
  });

  it("all three extend the mocked CredentialsSignin base class", async () => {
    const { CredentialsSignin } = await import("next-auth");
    expect(new MfaRequiredError()).toBeInstanceOf(CredentialsSignin);
    expect(new MfaRequiredSetupError()).toBeInstanceOf(CredentialsSignin);
    expect(new InvalidTotpError()).toBeInstanceOf(CredentialsSignin);
  });

  it("error class names are descriptive (not generic 'Error')", () => {
    expect(new MfaRequiredError().constructor.name).toBe("MfaRequiredError");
    expect(new MfaRequiredSetupError().constructor.name).toBe("MfaRequiredSetupError");
    expect(new InvalidTotpError().constructor.name).toBe("InvalidTotpError");
  });
});
