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

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

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

describe("devApi", () => {
  beforeEach(() => {
    apiClient.get.mockReset();
    apiClient.post.mockReset();
    apiClient.put.mockReset();
    apiClient.patch.mockReset();
    apiClient.delete.mockReset();
  });

  it("fetches list and detail resources with expected query parameters", async () => {
    const {
      fetchClients,
      fetchDevStats,
      fetchDevRPUsageDaily,
      fetchTenants,
      fetchClient,
      fetchClientRelations,
      fetchRPUserMetadata,
      fetchDevUsers,
      fetchConsents,
      fetchDevAuditLogs,
      fetchMyTenants,
      fetchDeveloperRequestStatus,
      fetchDeveloperRequests,
      listIdpConfigsForClient,
    } = await import("./devApi");
    apiClient.get.mockResolvedValue({ data: { ok: true } });

    await fetchClients();
    await fetchDevStats();
    await fetchDevRPUsageDaily({ days: 30, period: "week" });
    await fetchTenants(25, 50, "tenant-parent");
    await fetchClient("client-a");
    await fetchClientRelations("client-a");
    await fetchRPUserMetadata("client-a", "user-a");
    await fetchDevUsers("admin", 5, "client-a");
    await fetchConsents("user-a", "client-a", "active");
    await fetchDevAuditLogs(10, "cursor-a", {
      action: "client.update",
      client_id: "client-a",
      status: "success",
      tenant_id: "tenant-a",
    });
    await fetchMyTenants();
    await fetchDeveloperRequestStatus("tenant-a");
    await fetchDeveloperRequests("pending");
    await listIdpConfigsForClient("client-a");

    expect(apiClient.get).toHaveBeenCalledWith("/dev/clients");
    expect(apiClient.get).toHaveBeenCalledWith("/dev/stats");
    expect(apiClient.get).toHaveBeenCalledWith("/dev/rp-usage/daily", {
      params: { days: 30, period: "week" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/tenants", {
      params: { limit: 25, offset: 50, parentId: "tenant-parent" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/dev/clients/client-a");
    expect(apiClient.get).toHaveBeenCalledWith(
      "/dev/clients/client-a/relations",
    );
    expect(apiClient.get).toHaveBeenCalledWith(
      "/dev/clients/client-a/users/user-a/metadata",
    );
    expect(apiClient.get).toHaveBeenCalledWith("/dev/users", {
      params: { search: "admin", limit: 5, clientId: "client-a" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/dev/consents", {
      params: { subject: "user-a", client_id: "client-a", status: "active" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/dev/audit-logs", {
      params: {
        limit: 10,
        cursor: "cursor-a",
        action: "client.update",
        client_id: "client-a",
        status: "success",
        tenant_id: "tenant-a",
      },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/dev/my-tenants");
    expect(apiClient.get).toHaveBeenCalledWith(
      "/dev/developer-request/status",
      {
        params: { tenantId: "tenant-a" },
      },
    );
    expect(apiClient.get).toHaveBeenCalledWith("/dev/developer-request/list", {
      params: { status: "pending" },
    });
    expect(apiClient.get).toHaveBeenCalledWith("/dev/clients/client-a/idps");
  });

  it("omits optional consent filters when they are empty or all", async () => {
    const { fetchConsents, revokeConsent } = await import("./devApi");
    apiClient.get.mockResolvedValue({ data: { items: [] } });
    apiClient.delete.mockResolvedValue({ data: {} });

    await fetchConsents("user-a", undefined, "all");
    await revokeConsent("user-a");

    expect(apiClient.get).toHaveBeenCalledWith("/dev/consents", {
      params: { subject: "user-a" },
    });
    expect(apiClient.delete).toHaveBeenCalledWith("/dev/consents", {
      params: { subject: "user-a" },
    });
  });

  it("sends mutation requests to the documented dev endpoints", async () => {
    const {
      addClientRelation,
      removeClientRelation,
      updateRPUserMetadata,
      updateClientStatus,
      createClient,
      updateClient,
      rotateClientSecret,
      refreshHeadlessJwksCache,
      revokeHeadlessJwksCache,
      deleteClient,
      revokeConsent,
      createIdpConfigForClient,
      updateIdpConfig,
      deleteIdpConfig,
      requestDeveloperAccess,
      approveDeveloperRequest,
      rejectDeveloperRequest,
      cancelDeveloperRequestApproval,
    } = await import("./devApi");
    apiClient.post.mockResolvedValue({ data: { ok: true } });
    apiClient.put.mockResolvedValue({ data: { ok: true } });
    apiClient.patch.mockResolvedValue({ data: { ok: true } });
    apiClient.delete.mockResolvedValue({ data: {} });

    await addClientRelation("client-a", {
      relation: "admins",
      userId: "user-a",
    });
    await removeClientRelation("client-a", "admins", "User:user-a");
    await updateRPUserMetadata("client-a", "user-a", { approvalLevel: "A" });
    await updateClientStatus("client-a", "inactive");
    await createClient({ id: "client-a", name: "Console App" });
    await updateClient("client-a", { name: "Console App Updated" });
    await rotateClientSecret("client-a");
    await refreshHeadlessJwksCache("client-a");
    await revokeHeadlessJwksCache("client-a");
    await deleteClient("client-a");
    await revokeConsent("user-a", "client-a");
    await createIdpConfigForClient({
      client_id: "client-a",
      provider_type: "oidc",
      display_name: "OIDC Provider",
      status: "active",
    });
    await updateIdpConfig("client-a", "idp-a", { status: "inactive" });
    await deleteIdpConfig("client-a", "idp-a");
    await requestDeveloperAccess({
      name: "Dev User",
      organization: "Hanmac",
      reason: "Need RP access",
      tenantId: "tenant-a",
      accessPages: ["all"],
    });
    await approveDeveloperRequest(1, "approved");
    await rejectDeveloperRequest(2, "rejected");
    await cancelDeveloperRequestApproval(3, "cancelled");

    expect(apiClient.post).toHaveBeenCalledWith(
      "/dev/clients/client-a/relations",
      { relation: "admins", userId: "user-a" },
    );
    expect(apiClient.delete).toHaveBeenCalledWith(
      "/dev/clients/client-a/relations",
      {
        params: { relation: "admins", subject: "User:user-a" },
      },
    );
    expect(apiClient.put).toHaveBeenCalledWith(
      "/dev/clients/client-a/users/user-a/metadata",
      { metadata: { approvalLevel: "A" } },
    );
    expect(apiClient.patch).toHaveBeenCalledWith(
      "/dev/clients/client-a/status",
      {
        status: "inactive",
      },
    );
    expect(apiClient.post).toHaveBeenCalledWith("/dev/clients", {
      id: "client-a",
      name: "Console App",
    });
    expect(apiClient.put).toHaveBeenCalledWith("/dev/clients/client-a", {
      name: "Console App Updated",
    });
    expect(apiClient.post).toHaveBeenCalledWith(
      "/dev/clients/client-a/secret/rotate",
    );
    expect(apiClient.post).toHaveBeenCalledWith(
      "/dev/clients/client-a/headless-jwks/refresh",
    );
    expect(apiClient.delete).toHaveBeenCalledWith(
      "/dev/clients/client-a/headless-jwks/cache",
    );
    expect(apiClient.delete).toHaveBeenCalledWith("/dev/clients/client-a");
    expect(apiClient.delete).toHaveBeenCalledWith("/dev/consents", {
      params: { subject: "user-a", client_id: "client-a" },
    });
    expect(apiClient.post).toHaveBeenCalledWith("/dev/clients/client-a/idps", {
      client_id: "client-a",
      provider_type: "oidc",
      display_name: "OIDC Provider",
      status: "active",
    });
    expect(apiClient.put).toHaveBeenCalledWith(
      "/dev/clients/client-a/idps/idp-a",
      {
        status: "inactive",
      },
    );
    expect(apiClient.delete).toHaveBeenCalledWith(
      "/dev/clients/client-a/idps/idp-a",
    );
    expect(apiClient.post).toHaveBeenCalledWith("/dev/developer-request", {
      name: "Dev User",
      organization: "Hanmac",
      reason: "Need RP access",
      tenantId: "tenant-a",
      accessPages: ["all"],
    });
    expect(apiClient.post).toHaveBeenCalledWith(
      "/dev/developer-request/1/approve",
      {
        adminNotes: "approved",
      },
    );
    expect(apiClient.post).toHaveBeenCalledWith(
      "/dev/developer-request/2/reject",
      {
        adminNotes: "rejected",
      },
    );
    expect(apiClient.post).toHaveBeenCalledWith(
      "/dev/developer-request/3/cancel-approval",
      {
        adminNotes: "cancelled",
      },
    );
  });
});
