import { expect, test } from "bun:test";
import {
  createPersistentTenantDirectory,
  memoryTenantDirectoryStore,
  migrateTenants,
  postgresTenantDirectoryStore,
} from "../src/index.ts";

test("persistent tenant directory stores memberships, workspace access and quota usage", async () => {
  const events: string[] = [];
  const directory = createPersistentTenantDirectory(memoryTenantDirectoryStore(), {
    audit: (event) => {
      events.push(event.action);
    },
  });
  await directory.addMembership({
    tenantId: "acme",
    userId: "u1",
    roles: ["admin"],
    workspaceIds: ["w1"],
  });
  expect(await directory.membership("acme", "u1")).toMatchObject({ roles: ["admin"] });
  expect(await directory.switchWorkspace("acme", "u1", "w1")).toEqual({
    tenantId: "acme",
    workspaceId: "w1",
  });
  await directory.setQuota("acme", "projects", 2);
  expect(await directory.consumeQuota("acme", "projects", 1)).toMatchObject({ usage: 1 });
  await expect(directory.consumeQuota("acme", "projects", 2)).rejects.toThrow("QUOTA");
  expect(events).toEqual(["membership.added", "workspace.switched"]);
});

test("tenant migration orchestrator bounds concurrency and reports isolated failures", async () => {
  let active = 0,
    peak = 0;
  const result = await migrateTenants(
    [{ id: "a" }, { id: "b" }, { id: "bad" }],
    async (tenant) => {
      active++;
      peak = Math.max(peak, active);
      await Promise.resolve();
      active--;
      if (tenant.id === "bad") throw new Error("migration failed");
    },
    { concurrency: 2, continueOnError: true },
  );
  expect(result.migrated.sort()).toEqual(["a", "b"]);
  expect(result.failed[0]?.tenantId).toBe("bad");
  expect(peak).toBeLessThanOrEqual(2);
});

test("PostgreSQL tenant store parameterizes identities", async () => {
  const calls: unknown[][] = [];
  const store = postgresTenantDirectoryStore({
    async query<T>(_sql: string, params?: unknown[]) {
      calls.push(params ?? []);
      return { rows: [] as T[] };
    },
  });
  await store.putMembership({ tenantId: "tenant", userId: "user" });
  expect(calls[0]?.slice(0, 2)).toEqual(["tenant", "user"]);
});
