import { describe, it, expect, vi } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useListData } from "../useListData";

describe("useListData", () => {
  it("loads items and updates loading", async () => {
    const fetcher = vi.fn().mockResolvedValue({ items: ["one", "two"] });
    const selector = vi.fn((response: { items: string[] }) => response.items);

    const { result } = renderHook(() =>
      useListData({
        fetcher,
        selector,
        errorMessage: "Failed to load",
      })
    );

    expect(result.current.loading).toBe(true);
    expect(result.current.items).toEqual([]);

    await act(async () => {
      await Promise.resolve();
    });

    expect(fetcher).toHaveBeenCalledTimes(1);
    expect(selector).toHaveBeenCalledWith({ items: ["one", "two"] });
    expect(result.current.items).toEqual(["one", "two"]);
    expect(result.current.loading).toBe(false);
  });

  it("sets error when the fetcher rejects", async () => {
    const fetcher = vi.fn().mockRejectedValue(new Error("network"));
    const selector = vi.fn();

    const { result } = renderHook(() =>
      useListData({
        fetcher,
        selector,
        errorMessage: "Failed to load",
      })
    );

    await act(async () => {
      await Promise.resolve();
    });

    expect(result.current.error).toBe("network");
    expect(result.current.loading).toBe(false);
    expect(result.current.items).toEqual([]);
  });

  it("refresh triggers a second fetch", async () => {
    const fetcher = vi.fn()
      .mockResolvedValueOnce({ items: ["first"] })
      .mockResolvedValueOnce({ items: ["second"] });
    const selector = vi.fn((response: { items: string[] }) => response.items);

    const { result } = renderHook(() =>
      useListData({
        fetcher,
        selector,
        errorMessage: "Failed to load",
      })
    );

    await act(async () => {
      await Promise.resolve();
    });

    expect(result.current.items).toEqual(["first"]);
    await act(async () => {
      result.current.refresh();
      await Promise.resolve();
    });

    expect(fetcher).toHaveBeenCalledTimes(2);
    expect(result.current.items).toEqual(["second"]);
  });
});
