import { describe, it, expect, vi } from "vitest";
import { createAuditRouter } from "./router";
import type { IAuditLog } from "../../audit-log.interface";
import type { AdminTrpcUser } from "./procedures";

/**
 * Minimal harness: create a tRPC caller directly from the router so we
 * don't need a real HTTP layer.
 */
function makeCallerWithUser(
  auditLog: IAuditLog,
  user?: AdminTrpcUser,
) {
  const router = createAuditRouter(auditLog);
  // Use the tRPC caller factory to invoke mutations directly in tests.
  return router.createCaller({ user } as Record<string, unknown>);
}

function makeAuditLog(): IAuditLog {
  return {
    record: vi.fn().mockResolvedValue(undefined),
    eraseSubject: vi.fn().mockResolvedValue(undefined),
  };
}

describe("auditRouter.eraseSubject", () => {
  it("throws FORBIDDEN when ctx.user is absent", async () => {
    const auditLog = makeAuditLog();
    const caller = makeCallerWithUser(auditLog, undefined);

    await expect(
      caller.eraseSubject({ actorId: "user_1", mode: "pseudonymize" }),
    ).rejects.toMatchObject({ code: "FORBIDDEN" });

    expect(auditLog.eraseSubject).not.toHaveBeenCalled();
  });

  it("throws FORBIDDEN when user lacks admin role", async () => {
    const auditLog = makeAuditLog();
    const caller = makeCallerWithUser(auditLog, { roles: ["editor", "viewer"] });

    await expect(
      caller.eraseSubject({ actorId: "user_1", mode: "pseudonymize" }),
    ).rejects.toMatchObject({ code: "FORBIDDEN" });

    expect(auditLog.eraseSubject).not.toHaveBeenCalled();
  });

  it("calls eraseSubject with pseudonymize mode for an admin user", async () => {
    const auditLog = makeAuditLog();
    const caller = makeCallerWithUser(auditLog, { roles: ["admin"] });

    const result = await caller.eraseSubject({
      actorId: "user_1",
      mode: "pseudonymize",
    });

    expect(result).toEqual({ ok: true });
    expect(auditLog.eraseSubject).toHaveBeenCalledWith("user_1", "pseudonymize");
  });

  it("calls eraseSubject with delete mode for an admin user", async () => {
    const auditLog = makeAuditLog();
    const caller = makeCallerWithUser(auditLog, { roles: ["admin"] });

    const result = await caller.eraseSubject({
      actorId: "user_2",
      mode: "delete",
    });

    expect(result).toEqual({ ok: true });
    expect(auditLog.eraseSubject).toHaveBeenCalledWith("user_2", "delete");
  });

  it("defaults mode to 'pseudonymize' when not provided", async () => {
    const auditLog = makeAuditLog();
    const caller = makeCallerWithUser(auditLog, { roles: ["admin"] });

    // mode has a .default("pseudonymize") in the schema
    await caller.eraseSubject({ actorId: "user_3", mode: "pseudonymize" });

    expect(auditLog.eraseSubject).toHaveBeenCalledWith("user_3", "pseudonymize");
  });

  it("rejects empty actorId (schema validation)", async () => {
    const auditLog = makeAuditLog();
    const caller = makeCallerWithUser(auditLog, { roles: ["admin"] });

    await expect(
      caller.eraseSubject({ actorId: "", mode: "pseudonymize" }),
    ).rejects.toThrow();
  });
});
