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

const apiClient = {
  get: vi.fn(),
  post: vi.fn(),
  put: vi.fn(),
  delete: vi.fn(),
};

const fetchAllCursorPages = vi.fn(async () => ({
  items: [{ id: "tenant-1", name: "Tenant", slug: "tenant" }],
  total: 1,
}));

vi.mock("./apiClient", () => ({
  default: apiClient,
}));

vi.mock("./auth", () => ({
  userManager: {
    getUser: vi.fn(async () => ({ access_token: "access-token" })),
  },
}));

vi.mock("../../../common/core/pagination", () => ({
  fetchAllCursorPages,
}));

describe("orgfront adminApi user tenant payloads", () => {
  beforeEach(() => {
    apiClient.get.mockReset();
    apiClient.post.mockReset();
    apiClient.put.mockReset();
    apiClient.delete.mockReset();

    apiClient.get.mockResolvedValue({ data: { ok: true } });
    apiClient.post.mockResolvedValue({ data: { ok: true } });
    apiClient.put.mockResolvedValue({ data: { ok: true } });
    apiClient.delete.mockResolvedValue({ data: { ok: true } });
    fetchAllCursorPages.mockClear();
    window.localStorage.clear();
  });

  it("routes read APIs to their documented orgfront admin endpoints", async () => {
    const adminApi = await import("./adminApi");

    await adminApi.fetchAuditLogs(10, "cursor-a");
    await adminApi.fetchTenants(25, 50, "parent-1", "cursor-b");
    await adminApi.fetchAllTenants({ pageSize: 200, parentId: "parent-1" });
    await adminApi.fetchTenant("tenant-1");
    await adminApi.fetchTenantAdmins("tenant-1");
    await adminApi.fetchTenantOwners("tenant-1");
    await adminApi.fetchGroups("tenant-1");
    await adminApi.fetchGroup("tenant-1", "group-1");
    await adminApi.fetchImportProgress("tenant-1", "progress-1");
    await adminApi.fetchGroupRoles("tenant-1", "group-1");
    await adminApi.fetchApiKeys(20, 40);
    await adminApi.fetchUsers(30, 60, "admin", "tenant");
    await adminApi.fetchUser("user-1");
    await adminApi.fetchPasswordPolicy();
    await adminApi.fetchUserRpHistory("user-1");
    await adminApi.fetchMe();
    await adminApi.fetchRelyingParties("tenant-1");
    await adminApi.fetchAllRelyingParties();
    await adminApi.fetchRelyingParty("client-1");
    await adminApi.fetchRPOwners("client-1");
    await adminApi.fetchPublicOrgChart("public-token");
    await adminApi.fetchOrgChartSnapshot();

    expect(apiClient.get).toHaveBeenCalledWith("/v1/audit", {
      params: { limit: 10, cursor: "cursor-a" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/v1/admin/tenants", {
      params: {
        limit: 25,
        offset: 50,
        parentId: "parent-1",
        cursor: "cursor-b",
      },
    });
    expect(fetchAllCursorPages).toHaveBeenCalledWith(
      expect.objectContaining({
        path: "/v1/admin/tenants",
        pageSize: 200,
        params: { parentId: "parent-1" },
      }),
    );
    expect(apiClient.get).toHaveBeenCalledWith(
      "/v1/admin/tenants/tenant-1/organization/group-1/roles",
    );
    expect(apiClient.get).toHaveBeenCalledWith("/v1/public/orgchart", {
      params: { token: "public-token" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/v1/admin/orgchart/snapshot", {
      params: { cache: "redis" },
    });
  });

  it("routes mutation APIs to their documented orgfront admin endpoints", async () => {
    const adminApi = await import("./adminApi");

    await adminApi.createTenant({ name: "Tenant", slug: "tenant" });
    await adminApi.updateTenant("tenant-1", { status: "inactive" });
    await adminApi.deleteTenant("tenant-1");
    await adminApi.deleteTenantsBulk(["tenant-1"]);
    await adminApi.approveTenant("tenant-1");
    await adminApi.addTenantAdmin("tenant-1", "user-1");
    await adminApi.removeTenantAdmin("tenant-1", "user-1");
    await adminApi.addTenantOwner("tenant-1", "user-1");
    await adminApi.removeTenantOwner("tenant-1", "user-1");
    await adminApi.createGroup("tenant-1", { name: "Group" });
    await adminApi.deleteGroup("tenant-1", "group-1");
    await adminApi.addGroupMember("tenant-1", "group-1", "user-1");
    await adminApi.removeGroupMember("tenant-1", "group-1", "user-1");
    await adminApi.importOrgChart(
      "tenant-1",
      new File(["name"], "org.csv"),
      "progress-1",
    );
    await adminApi.assignGroupRole("tenant-1", "group-1", "tenant-2", "owner");
    await adminApi.removeGroupRole("tenant-1", "group-1", "tenant-2", "owner");
    await adminApi.createApiKey({ name: "key", scopes: ["read"] });
    await adminApi.deleteApiKey("key-1");
    await adminApi.createUser({ email: "user@example.com", name: "User" });
    await adminApi.bulkCreateUsers([
      { email: "user@example.com", name: "User", metadata: {} },
    ]);
    await adminApi.bulkUpdateUsers({ userIds: ["user-1"], status: "inactive" });
    await adminApi.bulkDeleteUsers(["user-1"]);
    await adminApi.updateUser("user-1", { status: "active" });
    await adminApi.deleteUser("user-1");
    await adminApi.createRelyingParty("tenant-1", {
      client_name: "RP",
      redirect_uris: ["https://rp.example/callback"],
    });
    await adminApi.updateRelyingParty("client-1", {
      client_name: "RP",
      redirect_uris: ["https://rp.example/callback"],
    });
    await adminApi.deleteRelyingParty("client-1");
    await adminApi.addRPOwner("client-1", "User:user-1");
    await adminApi.removeRPOwner("client-1", "User:user-1");

    expect(apiClient.post).toHaveBeenCalledWith(
      "/v1/admin/tenants/tenant-1/organization/group-1/members",
      { userId: "user-1" },
    );
    expect(apiClient.post).toHaveBeenCalledWith(
      "/v1/admin/tenants/tenant-1/organization/import?progressId=progress-1",
      expect.any(FormData),
      { headers: { "Content-Type": "multipart/form-data" } },
    );
    expect(apiClient.put).toHaveBeenCalledWith("/v1/admin/users/user-1", {
      status: "active",
    });
    expect(apiClient.delete).toHaveBeenCalledWith(
      "/v1/admin/relying-parties/client-1/owners/User:user-1",
    );
  });

  it("sends tenantSlug without remapping it to companyCode when creating a user", async () => {
    const { createUser } = await import("./adminApi");

    await createUser({
      email: "user@test.com",
      name: "Test User",
      tenantSlug: "test-tenant",
    });

    expect(apiClient.post).toHaveBeenCalledWith(
      "/v1/admin/users",
      expect.objectContaining({ tenantSlug: "test-tenant" }),
    );
    expect(apiClient.post.mock.calls[0][1]).not.toHaveProperty("companyCode");
  });

  it("sends tenantSlug without remapping it to companyCode when updating a user", async () => {
    const { updateUser } = await import("./adminApi");

    await updateUser("user-id", { tenantSlug: "new-tenant" });

    expect(apiClient.put).toHaveBeenCalledWith(
      "/v1/admin/users/user-id",
      expect.objectContaining({ tenantSlug: "new-tenant" }),
    );
    expect(apiClient.put.mock.calls[0][1]).not.toHaveProperty("companyCode");
  });

  it("keeps tenantSlug payloads unchanged for bulk user APIs", async () => {
    const { bulkCreateUsers, bulkUpdateUsers } = await import("./adminApi");

    await bulkCreateUsers([
      {
        email: "user@test.com",
        name: "Test User",
        tenantSlug: "test-tenant",
        metadata: {},
      },
    ]);
    await bulkUpdateUsers({
      userIds: ["user-id"],
      tenantSlug: "new-tenant",
    });

    expect(apiClient.post.mock.calls[0][1].users[0]).toMatchObject({
      tenantSlug: "test-tenant",
    });
    expect(apiClient.post.mock.calls[0][1].users[0]).not.toHaveProperty(
      "companyCode",
    );
    expect(apiClient.put.mock.calls[0][1]).toMatchObject({
      tenantSlug: "new-tenant",
    });
    expect(apiClient.put.mock.calls[0][1]).not.toHaveProperty("companyCode");
  });
});
