import { afterEach, expect, test, vi } from "vitest";
import { setAccessToken } from "@/shared/api/request";
import {
    adminAddAgencyHost,
    createBDLeader,
    createCountry,
    createCoinSeller,
    createManager,
    createRegion,
    creditCoinSellerStock,
    debitCoinSellerStock,
    deleteAgency,
    disableRegion,
    listAgencies,
    listBDs,
    listCoinSellerSubApplications,
    listCoinSellerSubSellers,
    listCoinSellers,
    listCountries,
    listHosts,
    listManagers,
    listRegions,
    getJob,
    renameCountryCode,
    replaceRegionCountries,
    approveCoinSellerSubApplication,
    rejectCoinSellerSubApplication,
    setCoinSellerStatus,
    updateBDLeaderPositionAlias,
    updateCountry,
    updateManager,
} from "./api";

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

test("host org list APIs use generated admin paths and filters", async () => {
    vi.stubGlobal(
        "fetch",
        vi.fn(
            async () => new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 10, total: 0 } })),
        ),
    );

    await listBDs({
        page: 1,
        page_size: 10,
        parent_leader_user_id: 21,
        region_id: 7,
        sort_by: "salary_wallet",
        sort_direction: "asc",
        status: "active",
    });
    await listAgencies({
        keyword: "agency",
        page: 2,
        page_size: 10,
        parent_bd_user_id: 31,
        sort_by: "salary_wallet",
        sort_direction: "desc",
    });
    await listManagers({
        keyword: "manager",
        page: 1,
        page_size: 10,
        region_id: 7,
        status: "active",
    });
    await createManager({
        canManageCrossRegion: false,
        canBlockUser: false,
        canGrantBadge: false,
        canGrantVip: true,
        contact: "+63",
        targetUserId: "1003",
    });
    await updateManager("1003", {
        canManageCrossRegion: true,
        canBlockUser: false,
        canGrantVehicle: true,
        canGrantVip: false,
        canTransferUserCountry: false,
        contact: "+63",
        status: "disabled",
    });
    await listHosts({ agency_id: 41, page: 1, page_size: 10, sort_by: "diamond", sort_direction: "desc" });
    await listCoinSellers({
        page: 1,
        page_size: 10,
        region_id: 7,
        sort_by: "merchant_balance",
        sort_direction: "desc",
        status: "active",
    });
    await createBDLeader({
        commandId: "bd-leader-test",
        positionAlias: "Senior Admin",
        targetUserId: "1002",
    });
    await updateBDLeaderPositionAlias("1002", {
        commandId: "bd-leader-position-alias-test",
        positionAlias: "Regional Admin",
    });
    await createCoinSeller({ commandId: "coin-seller-test", reason: "contact", targetUserId: "1001" });
    await setCoinSellerStatus("1001", { commandId: "coin-seller-status-test", reason: "disable", status: "disabled" });
    await creditCoinSellerStock("1001", {
        coinAmount: 8000000,
        commandId: "coin-seller-stock-test",
        rechargeAmount: "100.000000",
        type: "usdt_purchase",
    });
    await debitCoinSellerStock("1001", {
        coinAmount: 1000,
        commandId: "coin-seller-stock-debit-test",
        rechargeAmount: "1.25",
        reason: "deduct bad stock",
    });
    await adminAddAgencyHost(7001, {
        commandId: "agency-add-host-test",
        reason: "manual add",
        targetUserId: "1004",
    });
    await deleteAgency(7001, { commandId: "agency-delete-test", reason: "cleanup" });

    const [bdUrl, bdInit] = vi.mocked(fetch).mock.calls[0];
    const [agencyUrl] = vi.mocked(fetch).mock.calls[1];
    const [managerUrl, managerInit] = vi.mocked(fetch).mock.calls[2];
    const [managerCreateUrl, managerCreateInit] = vi.mocked(fetch).mock.calls[3];
    const [managerUpdateUrl, managerUpdateInit] = vi.mocked(fetch).mock.calls[4];
    const [hostUrl] = vi.mocked(fetch).mock.calls[5];
    const [coinSellerUrl, coinSellerInit] = vi.mocked(fetch).mock.calls[6];
    const [bdLeaderCreateUrl, bdLeaderCreateInit] = vi.mocked(fetch).mock.calls[7];
    const [bdLeaderAliasUrl, bdLeaderAliasInit] = vi.mocked(fetch).mock.calls[8];
    const [coinSellerCreateUrl, coinSellerCreateInit] = vi.mocked(fetch).mock.calls[9];
    const [coinSellerStatusUrl, coinSellerStatusInit] = vi.mocked(fetch).mock.calls[10];
    const [coinSellerStockUrl, coinSellerStockInit] = vi.mocked(fetch).mock.calls[11];
    const [coinSellerStockDebitUrl, coinSellerStockDebitInit] = vi.mocked(fetch).mock.calls[12];
    const [agencyAddHostUrl, agencyAddHostInit] = vi.mocked(fetch).mock.calls[13];
    const [agencyDeleteUrl, agencyDeleteInit] = vi.mocked(fetch).mock.calls[14];

    expect(String(bdUrl)).toContain("/api/v1/admin/bds?");
    expect(String(bdUrl)).toContain("parent_leader_user_id=21");
    expect(String(bdUrl)).toContain("region_id=7");
    expect(String(bdUrl)).toContain("sort_by=salary_wallet");
    expect(String(bdUrl)).toContain("sort_direction=asc");
    expect(String(bdUrl)).toContain("status=active");
    expect(bdInit?.method).toBe("GET");
    expect(String(agencyUrl)).toContain("/api/v1/admin/agencies?");
    expect(String(agencyUrl)).toContain("parent_bd_user_id=31");
    expect(String(agencyUrl)).toContain("sort_by=salary_wallet");
    expect(String(agencyUrl)).toContain("sort_direction=desc");
    expect(String(managerUrl)).toContain("/api/v1/admin/managers?");
    expect(String(managerUrl)).toContain("keyword=manager");
    expect(String(managerUrl)).toContain("region_id=7");
    expect(String(managerUrl)).toContain("status=active");
    expect(String(managerUrl)).not.toContain("parent_bd_user_id");
    expect(managerInit?.method).toBe("GET");
    expect(String(managerCreateUrl)).toContain("/api/v1/admin/managers");
    expect(managerCreateInit?.method).toBe("POST");
    expect(JSON.parse(String(managerCreateInit?.body))).toEqual({
        canManageCrossRegion: false,
        canBlockUser: false,
        canGrantBadge: false,
        canGrantVip: true,
        contact: "+63",
        targetUserId: "1003",
    });
    expect(String(managerUpdateUrl)).toContain("/api/v1/admin/managers/1003");
    expect(managerUpdateInit?.method).toBe("PUT");
    expect(JSON.parse(String(managerUpdateInit?.body))).toEqual({
        canManageCrossRegion: true,
        canBlockUser: false,
        canGrantVehicle: true,
        canGrantVip: false,
        canTransferUserCountry: false,
        contact: "+63",
        status: "disabled",
    });
    expect(String(hostUrl)).toContain("/api/v1/admin/hosts?");
    expect(String(hostUrl)).toContain("agency_id=41");
    expect(String(hostUrl)).toContain("sort_by=diamond");
    expect(String(hostUrl)).toContain("sort_direction=desc");
    expect(String(coinSellerUrl)).toContain("/api/v1/admin/coin-sellers?");
    expect(String(coinSellerUrl)).toContain("region_id=7");
    expect(String(coinSellerUrl)).toContain("sort_by=merchant_balance");
    expect(String(coinSellerUrl)).toContain("sort_direction=desc");
    expect(String(coinSellerUrl)).toContain("status=active");
    expect(coinSellerInit?.method).toBe("GET");
    expect(String(bdLeaderCreateUrl)).toContain("/api/v1/admin/bd-leaders");
    expect(bdLeaderCreateInit?.method).toBe("POST");
    expect(JSON.parse(String(bdLeaderCreateInit?.body))).toMatchObject({ positionAlias: "Senior Admin" });
    expect(JSON.parse(String(bdLeaderCreateInit?.body))).not.toHaveProperty("regionId");
    expect(String(bdLeaderAliasUrl)).toContain("/api/v1/admin/bd-leaders/1002/position-alias");
    expect(bdLeaderAliasInit?.method).toBe("PATCH");
    expect(JSON.parse(String(bdLeaderAliasInit?.body))).toMatchObject({ positionAlias: "Regional Admin" });
    expect(String(coinSellerCreateUrl)).toContain("/api/v1/admin/coin-sellers");
    expect(coinSellerCreateInit?.method).toBe("POST");
    expect(String(coinSellerStatusUrl)).toContain("/api/v1/admin/coin-sellers/1001/status");
    expect(coinSellerStatusInit?.method).toBe("PATCH");
    expect(String(coinSellerStockUrl)).toContain("/api/v1/admin/coin-sellers/1001/stock-credits");
    expect(coinSellerStockInit?.method).toBe("POST");
    expect(String(coinSellerStockDebitUrl)).toContain("/api/v1/admin/coin-sellers/1001/stock-debits");
    expect(coinSellerStockDebitInit?.method).toBe("POST");
    expect(String(agencyAddHostUrl)).toContain("/api/v1/admin/agencies/7001/hosts");
    expect(agencyAddHostInit?.method).toBe("POST");
    expect(JSON.parse(String(agencyAddHostInit?.body))).toMatchObject({
        commandId: "agency-add-host-test",
        targetUserId: "1004",
    });
    expect(String(agencyDeleteUrl)).toContain("/api/v1/admin/agencies/7001/delete");
    expect(agencyDeleteInit?.method).toBe("POST");
    expect(JSON.parse(String(agencyDeleteInit?.body))).toMatchObject({ commandId: "agency-delete-test" });
});

test("coin seller sub application APIs use generated admin paths", async () => {
    vi.stubGlobal(
        "fetch",
        vi.fn(
            async () => new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 10, total: 0 } })),
        ),
    );

    await listCoinSellerSubSellers("3001", { page: 1, page_size: 10 });
    await listCoinSellerSubApplications({
        keyword: "163001",
        page: 2,
        page_size: 10,
        parent_user_id: "3001",
        status: "pending",
        target_user_id: "3002",
    });
    await approveCoinSellerSubApplication("sub-app-1", {
        commandId: "approve-sub-app-test",
        reason: "ok",
    });
    await rejectCoinSellerSubApplication("sub-app-2", {
        commandId: "reject-sub-app-test",
        reason: "bad",
    });

    const [subSellerUrl, subSellerInit] = vi.mocked(fetch).mock.calls[0];
    const [applicationUrl, applicationInit] = vi.mocked(fetch).mock.calls[1];
    const [approveUrl, approveInit] = vi.mocked(fetch).mock.calls[2];
    const [rejectUrl, rejectInit] = vi.mocked(fetch).mock.calls[3];

    expect(String(subSellerUrl)).toContain("/api/v1/admin/coin-sellers/3001/sub-sellers?");
    expect(String(subSellerUrl)).toContain("page=1");
    expect(subSellerInit?.method).toBe("GET");
    expect(String(applicationUrl)).toContain("/api/v1/admin/coin-seller-sub-applications?");
    expect(String(applicationUrl)).toContain("keyword=163001");
    expect(String(applicationUrl)).toContain("parent_user_id=3001");
    expect(String(applicationUrl)).toContain("target_user_id=3002");
    expect(String(applicationUrl)).toContain("status=pending");
    expect(applicationInit?.method).toBe("GET");
    expect(String(approveUrl)).toContain("/api/v1/admin/coin-seller-sub-applications/sub-app-1/approve");
    expect(approveInit?.method).toBe("POST");
    expect(JSON.parse(String(approveInit?.body))).toMatchObject({ commandId: "approve-sub-app-test" });
    expect(String(rejectUrl)).toContain("/api/v1/admin/coin-seller-sub-applications/sub-app-2/reject");
    expect(rejectInit?.method).toBe("POST");
    expect(JSON.parse(String(rejectInit?.body))).toMatchObject({ commandId: "reject-sub-app-test" });
});

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

    await listCountries({ enabled: true });
    await createCountry({
        countryCode: "US",
        countryDisplayName: "United States",
        countryName: "United States",
        enabled: true,
    });
    await updateCountry(12, { countryDisplayName: "United States", countryName: "United States" });
    await renameCountryCode(12, {
        countryCode: "USA",
        countryDisplayName: "United States",
        countryName: "United States",
        sortOrder: 10,
    });
    await getJob(99);
    await listRegions({ status: "active" });
    await createRegion({ countries: ["US"], name: "North America", regionCode: "NA" });
    await replaceRegionCountries(7, { countries: ["US", "CA"] });
    await disableRegion(7);

    const [countryListUrl, countryListInit] = vi.mocked(fetch).mock.calls[0];
    const [countryCreateUrl, countryCreateInit] = vi.mocked(fetch).mock.calls[1];
    const [countryUpdateUrl, countryUpdateInit] = vi.mocked(fetch).mock.calls[2];
    const [countryRenameUrl, countryRenameInit] = vi.mocked(fetch).mock.calls[3];
    const [jobUrl, jobInit] = vi.mocked(fetch).mock.calls[4];
    const [regionListUrl, regionListInit] = vi.mocked(fetch).mock.calls[5];
    const [regionCreateUrl, regionCreateInit] = vi.mocked(fetch).mock.calls[6];
    const [regionCountriesUrl, regionCountriesInit] = vi.mocked(fetch).mock.calls[7];
    const [regionDisableUrl, regionDisableInit] = vi.mocked(fetch).mock.calls[8];

    expect(String(countryListUrl)).toContain("/api/v1/admin/countries?");
    expect(String(countryListUrl)).toContain("enabled=true");
    expect(countryListInit?.method).toBe("GET");
    expect(String(countryCreateUrl)).toContain("/api/v1/admin/countries");
    expect(countryCreateInit?.method).toBe("POST");
    expect(String(countryUpdateUrl)).toContain("/api/v1/admin/countries/12");
    expect(countryUpdateInit?.method).toBe("PATCH");
    expect(JSON.parse(String(countryUpdateInit?.body))).not.toHaveProperty("countryCode");
    expect(String(countryRenameUrl)).toContain("/api/v1/admin/countries/12/rename-code");
    expect(countryRenameInit?.method).toBe("POST");
    expect(JSON.parse(String(countryRenameInit?.body))).toMatchObject({ countryCode: "USA", sortOrder: 10 });
    expect(String(jobUrl)).toContain("/api/v1/jobs/99");
    expect(jobInit?.method).toBe("GET");
    expect(String(regionListUrl)).toContain("/api/v1/admin/regions?");
    expect(String(regionListUrl)).toContain("status=active");
    expect(regionListInit?.method).toBe("GET");
    expect(String(regionCreateUrl)).toContain("/api/v1/admin/regions");
    expect(regionCreateInit?.method).toBe("POST");
    expect(String(regionCountriesUrl)).toContain("/api/v1/admin/regions/7/countries");
    expect(regionCountriesInit?.method).toBe("PUT");
    expect(String(regionDisableUrl)).toContain("/api/v1/admin/regions/7");
    expect(regionDisableInit?.method).toBe("DELETE");
});
