import { afterEach, expect, test, vi } from "vitest";
import { setAccessToken } from "@/shared/api/request";
import { getFinanceScopeCatalog, getUserAppScopes, listFinanceScopeAssignments, listUserFinanceScopes, listUsers, replaceUserAppScopes, replaceUserFinanceScopes, updateUserStatus } from "./api";

afterEach(() => {
  setAccessToken("");
  vi.unstubAllGlobals();
});

test("listUsers uses generated endpoint path and query", async () => {
  vi.stubGlobal(
    "fetch",
    vi.fn(async () => new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 10, total: 0 } })))
  );

  const result = await listUsers({ page: 1, page_size: 10, status: "active", team_id: 2 });
  const [url, init] = vi.mocked(fetch).mock.calls[0];

  expect(result.items).toEqual([]);
  expect(String(url)).toContain("/api/v1/users?");
  expect(String(url)).toContain("page=1");
  expect(String(url)).toContain("page_size=10");
  expect(String(url)).toContain("status=active");
  expect(String(url)).toContain("team_id=2");
  expect(init?.method).toBe("GET");
});

test("updateUserStatus sends generated endpoint path and payload", async () => {
  vi.stubGlobal(
    "fetch",
    vi.fn(async () => new Response(JSON.stringify({ code: 0, data: { id: 7, name: "张三", account: "zhangsan", status: "locked" } })))
  );

  await updateUserStatus(7, "locked");
  const [url, init] = vi.mocked(fetch).mock.calls[0];

  expect(String(url)).toContain("/api/v1/users/7/status");
  expect(init?.method).toBe("PATCH");
  expect(JSON.parse(String(init?.body))).toEqual({ status: "locked" });
});

test("finance scope APIs use generated endpoint paths", async () => {
  vi.stubGlobal(
    "fetch",
    vi.fn(async () => new Response(JSON.stringify({ code: 0, data: { apps: [], items: [], total: 0 } })))
  );

  await listUserFinanceScopes(9);
  await replaceUserFinanceScopes(9, [{ appCode: "lalu", regionId: 2 }]);
  await getFinanceScopeCatalog();
  await listFinanceScopeAssignments();

  const calls = vi.mocked(fetch).mock.calls;
  expect(String(calls[0][0])).toContain("/api/v1/users/9/finance-scopes");
  expect(calls[0][1]?.method).toBe("GET");
  expect(String(calls[1][0])).toContain("/api/v1/users/9/finance-scopes");
  expect(calls[1][1]?.method).toBe("PUT");
  expect(JSON.parse(String(calls[1][1]?.body))).toEqual({ scopes: [{ appCode: "lalu", regionId: 2 }] });
  expect(String(calls[2][0])).toContain("/api/v1/admin/finance/scope");
  expect(calls[2][1]?.method).toBe("GET");
  expect(String(calls[3][0])).toContain("/api/v1/users/finance-scope-assignments");
  expect(calls[3][1]?.method).toBe("GET");
});

test("app scope APIs use generated endpoint paths and explicit mode", async () => {
  vi.stubGlobal(
    "fetch",
    vi.fn(async () => new Response(JSON.stringify({ code: 0, data: { appCodes: ["lalu"], mode: "selected" } })))
  );

  await getUserAppScopes(9);
  await replaceUserAppScopes(9, { appCodes: ["lalu"], mode: "selected" });

  const calls = vi.mocked(fetch).mock.calls;
  expect(String(calls[0][0])).toContain("/api/v1/users/9/app-scopes");
  expect(calls[0][1]?.method).toBe("GET");
  expect(String(calls[1][0])).toContain("/api/v1/users/9/app-scopes");
  expect(calls[1][1]?.method).toBe("PUT");
  expect(JSON.parse(String(calls[1][1]?.body))).toEqual({ appCodes: ["lalu"], mode: "selected" });
});
