// src/hooks/useApiOnMount.test.ts
import { renderHook, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { useApiOnMount } from './useApiOnMount';

// Create a mock API function that the hook will call.
// This allows us to control its behavior (success/failure) in our tests.
const mockApiFunction = vi.fn();

describe('useApiOnMount', () => {
  beforeEach(() => {
    // Clear mock history before each test to ensure isolation.
    vi.clearAllMocks();
  });

  it('should return loading: true on initial render', () => {
    // Arrange:
    // Mock the API function to return a promise that never resolves.
    // This keeps the hook in a perpetual "loading" state for the initial check.
    mockApiFunction.mockReturnValue(new Promise(() => {}));

    // Act:
    // Render the hook, which will immediately call the API function on mount.
    const { result } = renderHook(() => useApiOnMount(mockApiFunction));

    // Assert:
    // Check that the hook's initial state is correct.
    expect(result.current.loading).toBe(true);
    expect(result.current.data).toBeNull();
    expect(result.current.error).toBeNull();
    expect(mockApiFunction).toHaveBeenCalledTimes(1);
  });

  it('should return data on successful API call', async () => {
    // Arrange:
    // Mock the API function to resolve with a successful Response object.
    // The underlying `useApi` hook will handle the `.json()` parsing.
    const mockData = { message: 'Success!' };
    mockApiFunction.mockResolvedValue(new Response(JSON.stringify(mockData)));

    // Act:
    // Render the hook.
    const { result } = renderHook(() => useApiOnMount(mockApiFunction));

    // Assert:
    // Use `waitFor` to wait for the hook's state to update after the promise resolves.
    await waitFor(() => {
      // The hook should no longer be loading.
      expect(result.current.loading).toBe(false);
      // The data should be populated with our mock data.
      expect(result.current.data).toEqual(mockData);
      // There should be no error.
      expect(result.current.error).toBeNull();
    });
  });

  it('should return an error on failed API call', async () => {
    // Arrange:
    // Mock the API function to reject with an error.
    const mockError = new Error('API Failure');
    mockApiFunction.mockRejectedValue(mockError);

    // Act:
    // Render the hook.
    const { result } = renderHook(() => useApiOnMount(mockApiFunction));

    // Assert:
    // Use `waitFor` to wait for the hook's state to update after the promise rejects.
    await waitFor(() => {
      // The hook should no longer be loading.
      expect(result.current.loading).toBe(false);
      // Data should remain null.
      expect(result.current.data).toBeNull();
      // The error state should be populated with the error we threw.
      expect(result.current.error).toEqual(mockError);
    });
  });
});