import { fireEvent, render, screen } from "@testing-library/react";
import { afterEach, expect, test, vi } from "vitest";
import { HostWithdrawalsPage } from "./HostWithdrawalsPage.jsx";
import { useHostWithdrawalsPage } from "@/features/host-org/hooks/useHostWithdrawalsPage.js";

const mocks = vi.hoisted(() => ({
    changeIdentity: vi.fn(),
    changeKeyword: vi.fn(),
    changeRecordType: vi.fn(),
    changeStatus: vi.fn(),
    changeTimeRange: vi.fn(),
    dataTable: vi.fn(),
    resetFilters: vi.fn(),
}));

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

vi.mock("@/shared/ui/DataTable.jsx", () => ({
    DataTable: (props) => {
        mocks.dataTable(props);
        return (
            <div data-testid="host-withdrawals-table">
                {props.columns.map((column) => (
                    <div data-testid={`column-${column.key}`} key={column.key}>
                        {column.label}
                    </div>
                ))}
                {props.items.map((item) => (
                    <div data-testid={`row-${item.id}`} key={item.id}>
                        {props.columns.map((column) => (
                            <div key={column.key}>{column.render ? column.render(item) : item[column.key]}</div>
                        ))}
                    </div>
                ))}
            </div>
        );
    },
}));

vi.mock("@/shared/ui/TimeRangeFilter.jsx", () => ({
    TimeRangeFilter: ({ onChange }) => (
        <button type="button" onClick={() => onChange({ endMs: "2000", startMs: "1000" })}>
            时间
        </button>
    ),
}));

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

test("host withdrawals page renders salary transfer and withdrawal records", () => {
    vi.mocked(useHostWithdrawalsPage).mockReturnValue(pageFixture());

    render(<HostWithdrawalsPage />);

    expect(screen.getByText("工资转币商")).toBeInTheDocument();
    expect(screen.getByText("提现申请")).toBeInTheDocument();
    expect(screen.getByText("Host")).toBeInTheDocument();
    expect(screen.getByText("BD Leader/Admin")).toBeInTheDocument();
    expect(screen.getByText("$123.45")).toBeInTheDocument();
    expect(screen.getByText("1,112")).toBeInTheDocument();
    expect(screen.getByText("已完成")).toBeInTheDocument();
    expect(screen.getByText("待审核")).toBeInTheDocument();
    expect(screen.getByText("USDT-TRC20")).toBeInTheDocument();
    expect(screen.getByText("TRON9ADDRESS")).toBeInTheDocument();
    expect(screen.getByText("tx-salary-1")).toBeInTheDocument();
    expect(screen.getByText("9")).toBeInTheDocument();
});

test("host withdrawals filters are wired to the page hook", () => {
    vi.mocked(useHostWithdrawalsPage).mockReturnValue(pageFixture({ hasActiveFilters: true }));

    render(<HostWithdrawalsPage />);

    const props = mocks.dataTable.mock.calls.at(-1)?.[0];
    props.columns.find((column) => column.key === "recordType").filter.onChange("withdrawal");
    props.columns.find((column) => column.key === "identity").filter.onChange("bd_leader_admin");
    props.columns.find((column) => column.key === "sourceUser").filter.onChange("168557");
    props.columns.find((column) => column.key === "status").filter.onChange("approved");
    fireEvent.click(screen.getByRole("button", { name: "时间" }));
    fireEvent.click(screen.getByRole("button", { name: "重置" }));

    expect(mocks.changeRecordType).toHaveBeenCalledWith("withdrawal");
    expect(mocks.changeIdentity).toHaveBeenCalledWith("bd_leader_admin");
    expect(mocks.changeKeyword).toHaveBeenCalledWith("168557");
    expect(mocks.changeStatus).toHaveBeenCalledWith("approved");
    expect(mocks.changeTimeRange).toHaveBeenCalledWith({ endMs: "2000", startMs: "1000" });
    expect(mocks.resetFilters).toHaveBeenCalled();
});

function pageFixture(patch = {}) {
    return {
        abilities: { canView: true },
        changeIdentity: mocks.changeIdentity,
        changeKeyword: mocks.changeKeyword,
        changeRecordType: mocks.changeRecordType,
        changeStatus: mocks.changeStatus,
        changeTimeRange: mocks.changeTimeRange,
        data: {
            items: [salaryTransferFixture(), withdrawalFixture()],
            page: 1,
            pageSize: 50,
            total: 2,
        },
        error: null,
        hasActiveFilters: false,
        identity: "",
        keyword: "",
        loading: false,
        page: 1,
        recordType: "",
        reload: vi.fn(),
        resetFilters: mocks.resetFilters,
        setPage: vi.fn(),
        status: "",
        timeRange: { endMs: "", startMs: "" },
        ...patch,
    };
}

function salaryTransferFixture() {
    return {
        coinAmount: 1112,
        commandId: "cmd-salary-1",
        createdAtMs: 1780000000000,
        id: "salary_transfer:101",
        identity: "host",
        recordType: "salary_transfer",
        salaryAssetType: "HOST_SALARY_USD",
        sellerUser: {
            displayUserId: "168556",
            userId: "3001",
            username: "Coin Seller",
        },
        sellerUserId: "3001",
        sourceUser: {
            displayUserId: "168577",
            userId: "1001",
            username: "Raj",
        },
        sourceUserId: "1001",
        status: "completed",
        transactionId: "tx-salary-1",
        updatedAtMs: 1780000000000,
        usdMinorAmount: 12345,
    };
}

function withdrawalFixture() {
    return {
        applicationId: "9",
        coinAmount: 0,
        commandId: "freeze-cmd-9",
        createdAtMs: 1780000001000,
        freezeTransactionId: "freeze-tx-9",
        id: "withdrawal:9",
        identity: "bd_leader_admin",
        recordType: "withdrawal",
        salaryAssetType: "ADMIN_SALARY_USD",
        sourceUser: {
            displayUserId: "481479",
            userId: "2002",
            username: "Mao",
        },
        sourceUserId: "2002",
        status: "pending",
        updatedAtMs: 1780000001000,
        usdMinorAmount: 5000,
        withdrawAddress: "TRON9ADDRESS",
        withdrawMethod: "USDT-TRC20",
    };
}
