import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { afterEach, beforeEach, expect, test, vi } from "vitest";
import { ResourceListPage } from "./ResourceListPage.jsx";
import { useResourceListPage } from "@/features/resources/hooks/useResourcePages.js";

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

vi.mock("@/features/resources/hooks/useResourcePages.js", () => ({
    useResourceListPage: vi.fn(),
}));

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

beforeEach(() => {
    globalThis.ResizeObserver = class ResizeObserver {
        observe() {}
        disconnect() {}
    };
    mocks.deleteResources.mockResolvedValue([]);
});

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

test("resource list calls row delete action with the target resource", async () => {
    const page = pageFixture();
    vi.mocked(useResourceListPage).mockReturnValue(page);

    render(<ResourceListPage />);

    fireEvent.click(screen.getAllByRole("button", { name: "删除资源" })[0]);

    await waitFor(() => {
        expect(mocks.deleteResources).toHaveBeenCalledWith([page.data.items[0]]);
    });
});

test("resource list batch delete uses selected resources and clears selected rows after success", async () => {
    const page = pageFixture();
    mocks.deleteResources.mockResolvedValue([11, 12]);
    vi.mocked(useResourceListPage).mockReturnValue(page);

    render(<ResourceListPage />);

    fireEvent.click(screen.getByLabelText("选择 Rose"));
    fireEvent.click(screen.getByLabelText("选择 Ring"));
    fireEvent.click(screen.getByRole("button", { name: "批量删除资源（2）" }));

    await waitFor(() => {
        expect(mocks.deleteResources).toHaveBeenCalledWith(page.data.items);
    });
    await waitFor(() => {
        expect(screen.getByLabelText("选择 Rose")).not.toBeChecked();
        expect(screen.getByLabelText("选择 Ring")).not.toBeChecked();
    });
});

test("resource list hides delete actions without delete permission", () => {
    vi.mocked(useResourceListPage).mockReturnValue(
        pageFixture({
            abilities: {
                canCreate: false,
                canDelete: false,
                canUpdate: true,
                canUpload: true,
            },
        }),
    );

    render(<ResourceListPage />);

    expect(screen.queryByLabelText(/批量删除资源/)).not.toBeInTheDocument();
    expect(screen.queryByLabelText("删除资源")).not.toBeInTheDocument();
});

test("resource list disables other delete actions while a resource delete is running", () => {
    vi.mocked(useResourceListPage).mockReturnValue(pageFixture({ loadingAction: "resource-delete-11" }));

    render(<ResourceListPage />);

    expect(screen.getByRole("button", { name: "删除中" })).toBeDisabled();
    expect(screen.getByRole("button", { name: "删除资源" })).toBeDisabled();
    expect(screen.getByRole("button", { name: "批量删除资源（0）" })).toBeDisabled();
    expect(screen.getByLabelText("选择 Rose")).toBeDisabled();
});

function pageFixture(patch = {}) {
    return {
        abilities: {
            canCreate: true,
            canDelete: true,
            canUpdate: true,
            canUpload: true,
        },
        activeAction: "",
        changeQuery: vi.fn(),
        changeResourceType: vi.fn(),
        changeStatus: vi.fn(),
        closeAction: vi.fn(),
        data: {
            items: [resourceFixture({ resourceId: 11, name: "Rose" }), resourceFixture({ resourceId: 12, name: "Ring" })],
            page: 1,
            pageSize: 50,
            total: 2,
        },
        deleteResources: mocks.deleteResources,
        error: null,
        form: {},
        loading: false,
        loadingAction: "",
        openCreateResource: vi.fn(),
        openEditResource: vi.fn(),
        page: 1,
        query: "",
        reload: vi.fn(),
        resetFilters: vi.fn(),
        resourceType: "",
        selectedResource: null,
        setForm: vi.fn(),
        setPage: vi.fn(),
        status: "",
        submitResource: vi.fn(),
        toggleManagerGrant: vi.fn(),
        toggleResource: vi.fn(),
        ...patch,
    };
}

function resourceFixture(patch = {}) {
    return {
        assetUrl: "https://media.example.com/resource.png",
        coinPrice: 10,
        managerGrantEnabled: false,
        name: "Rose",
        previewUrl: "https://media.example.com/cover.png",
        priceType: "coin",
        resourceCode: "gift_rose",
        resourceId: 11,
        resourceType: "gift",
        status: "active",
        updatedAtMs: 1782287714973,
        ...patch,
    };
}
