import { renderHook, act } from "@testing-library/react";
import { useUserSearch } from "@/components/Attendees/useUserSearch";
import { searchUsers } from "@/features/User/userAPI";

jest.mock("@/features/User/userAPI", () => ({
  searchUsers: jest.fn(),
}));

describe("useUserSearch", () => {
  const mockSearchUsers = searchUsers as jest.Mock;

  beforeEach(() => {
    jest.useFakeTimers();
    jest.clearAllMocks();
  });

  afterEach(() => {
    jest.useRealTimers();
  });

  it("should initialize with default values", () => {
    const { result } = renderHook(() =>
      useUserSearch({ objectTypes: ["user"], errorMessage: "Error" })
    );

    expect(result.current.query).toBe("");
    expect(result.current.loading).toBe(false);
    expect(result.current.options).toEqual([]);
    expect(result.current.hasSearched).toBe(false);
    expect(result.current.isOpen).toBe(false);
    expect(result.current.inputError).toBeNull();
    expect(result.current.snackbarOpen).toBe(false);
    expect(result.current.snackbarMessage).toBe("");
  });

  it("should debounce and fetch users when query changes", async () => {
    const mockUsers = [{ displayName: "John Doe", email: "john@example.com" }];
    mockSearchUsers.mockResolvedValueOnce(mockUsers);

    const { result } = renderHook(() =>
      useUserSearch({ objectTypes: ["user"], errorMessage: "Error" })
    );

    act(() => {
      result.current.setQuery("John");
    });

    expect(result.current.loading).toBe(false); // Before debounce

    // Wait for the mock promise to resolve within act
    await act(async () => {
      jest.advanceTimersByTime(300);
      await Promise.resolve(); // allow microtasks to flush
    });

    expect(mockSearchUsers).toHaveBeenCalledWith("John", ["user"]);
    expect(result.current.loading).toBe(false);
    expect(result.current.options).toEqual(mockUsers);
    expect(result.current.hasSearched).toBe(true);
  });

  it("should clear options and handle empty query", () => {
    const { result } = renderHook(() =>
      useUserSearch({ objectTypes: ["user"], errorMessage: "Error" })
    );

    act(() => {
      result.current.setQuery("   "); // empty query with spaces
    });

    act(() => {
      jest.advanceTimersByTime(300);
    });

    expect(mockSearchUsers).not.toHaveBeenCalled();
    expect(result.current.options).toEqual([]);
    expect(result.current.loading).toBe(false);
    expect(result.current.hasSearched).toBe(false);
  });

  it("should handle search errors and show the custom error message", async () => {
    mockSearchUsers.mockRejectedValueOnce(new Error("API Error"));

    const { result } = renderHook(() =>
      useUserSearch({ objectTypes: ["user"], errorMessage: "Custom Error" })
    );

    act(() => {
      result.current.setQuery("FailedSearch");
    });

    await act(async () => {
      jest.advanceTimersByTime(300);
      await Promise.resolve(); // allow microtasks to flush
    });

    expect(result.current.hasSearched).toBe(false);
    expect(result.current.loading).toBe(false);
    expect(result.current.snackbarOpen).toBe(true);
    expect(result.current.snackbarMessage).toBe("Custom Error");
  });
});
