import { act, renderHook } from "@testing-library/react";
import { afterEach, expect, test, vi } from "vitest";
import { useHostCountriesPage } from "./useHostCountriesPage.js";
import { getJob, renameCountryCode, updateCountry } from "@/features/host-org/api";
import { useCountryAbilities } from "@/features/host-org/permissions.js";
import { useAdminQuery } from "@/shared/hooks/useAdminQuery.js";
import { useToast } from "@/shared/ui/ToastProvider.jsx";

const mocks = vi.hoisted(() => ({
    reload: vi.fn(),
    showToast: vi.fn(),
}));

vi.mock("@/features/host-org/api", () => ({
    createCountry: vi.fn(),
    disableCountry: vi.fn(),
    enableCountry: vi.fn(),
    getJob: vi.fn(),
    listCountries: vi.fn(),
    renameCountryCode: vi.fn(),
    updateCountry: vi.fn(),
}));

vi.mock("@/features/host-org/permissions.js", () => ({
    useCountryAbilities: vi.fn(),
}));

vi.mock("@/shared/hooks/useAdminQuery.js", () => ({
    useAdminQuery: vi.fn(),
}));

vi.mock("@/shared/ui/ToastProvider.jsx", () => ({
    useToast: vi.fn(),
}));

afterEach(() => {
    vi.clearAllMocks();
});

test("country edit without code change uses metadata update endpoint", async () => {
    mockHookDeps();
    vi.mocked(updateCountry).mockResolvedValue({ countryId: 12, countryCode: "PH" });
    const { result } = renderHook(() => useHostCountriesPage());

    act(() => {
        result.current.openEditCountry(countryFixture());
    });
    await act(async () => {
        await result.current.submitCountry({ preventDefault: vi.fn() });
    });

    expect(updateCountry).toHaveBeenCalledWith(
        12,
        expect.not.objectContaining({
            countryCode: expect.anything(),
        }),
    );
    expect(renameCountryCode).not.toHaveBeenCalled();
    expect(mocks.reload).toHaveBeenCalled();
});

test("country edit with code change creates rename job and polls until success", async () => {
    mockHookDeps();
    vi.mocked(renameCountryCode).mockResolvedValue({
        countryId: 12,
        jobId: 99,
        newCountryCode: "PHL",
        oldCountryCode: "PH",
        status: "pending",
    });
    vi.mocked(getJob).mockResolvedValue({ id: 99, status: "succeeded", type: "country-code-rename" });
    const { result } = renderHook(() => useHostCountriesPage());

    act(() => {
        result.current.openEditCountry(countryFixture());
    });
    act(() => {
        result.current.setCountryForm({ ...result.current.countryForm, countryCode: "phl" });
    });
    await act(async () => {
        await result.current.submitCountry({ preventDefault: vi.fn() });
    });

    expect(renameCountryCode).toHaveBeenCalledWith(
        12,
        expect.objectContaining({
            countryCode: "PHL",
            countryDisplayName: "菲律宾",
            countryName: "Philippines",
        }),
    );
    expect(getJob).toHaveBeenCalledWith(99);
    expect(updateCountry).not.toHaveBeenCalled();
    expect(mocks.showToast).toHaveBeenCalledWith("国家码重命名完成", "success");
    expect(mocks.reload).toHaveBeenCalled();
});

function mockHookDeps() {
    vi.mocked(useCountryAbilities).mockReturnValue({
        canCreate: true,
        canStatus: true,
        canUpdate: true,
        canView: true,
    });
    vi.mocked(useToast).mockReturnValue({ showToast: mocks.showToast });
    vi.mocked(useAdminQuery).mockReturnValue({
        data: { items: [], total: 0 },
        error: null,
        loading: false,
        reload: mocks.reload,
    });
}

function countryFixture() {
    return {
        countryCode: "PH",
        countryDisplayName: "菲律宾",
        countryId: 12,
        countryName: "Philippines",
        enabled: true,
        flag: "🇵🇭",
        isoAlpha3: "PHL",
        isoNumeric: "608",
        phoneCountryCode: "+63",
        sortOrder: 1770,
    };
}
