// src/hooks/useMasterItems.test.tsx
import React, { ReactNode } from 'react';
import { renderHook } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { useMasterItems } from './useMasterItems';
import { MasterItemsProvider } from '../providers/MasterItemsProvider';
import { useApiOnMount } from './useApiOnMount';
import type { MasterGroceryItem } from '../types';

// 1. Mock the useApiOnMount hook, which is the dependency of our provider.
vi.mock('./useApiOnMount');

// 2. Create a typed mock for type safety and autocompletion.
const mockedUseApiOnMount = vi.mocked(useApiOnMount);

// 3. A simple wrapper component that renders our provider.
// This is necessary because the useMasterItems hook needs to be a child of MasterItemsProvider.
const wrapper = ({ children }: { children: ReactNode }) => <MasterItemsProvider>{children}</MasterItemsProvider>;

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

  it('should throw an error if useMasterItems is used outside of MasterItemsProvider', () => {
    // Suppress the expected console.error for this test to keep the output clean.
    const originalError = console.error;
    console.error = vi.fn();
    
    // Expecting renderHook to throw an error because there's no provider.
    expect(() => renderHook(() => useMasterItems())).toThrow('useMasterItems must be used within a MasterItemsProvider');
    
    // Restore the original console.error function.
    console.error = originalError;
  });

  it('should return the initial loading state correctly', () => {
    // Arrange: Configure the mocked hook to return a loading state.
    mockedUseApiOnMount.mockReturnValue({
      data: null,
      loading: true,
      error: null,
      isRefetching: false,
      reset: vi.fn(),
    });

    // Act: Render the hook within the provider wrapper.
    const { result } = renderHook(() => useMasterItems(), { wrapper });

    // Assert: Check that the context values match the loading state.
    expect(result.current.isLoading).toBe(true);
    expect(result.current.masterItems).toEqual([]);
    expect(result.current.error).toBeNull();
  });

  it('should return masterItems on successful fetch', () => {
    // Arrange: Mock a successful data fetch.
    const mockItems: MasterGroceryItem[] = [
      { master_grocery_item_id: 1, name: 'Milk', category_id: 1, category_name: 'Dairy', created_at: '' },
      { master_grocery_item_id: 2, name: 'Bread', category_id: 2, category_name: 'Bakery', created_at: '' },
    ];
    mockedUseApiOnMount.mockReturnValue({
      data: mockItems,
      loading: false,
      error: null,
      isRefetching: false,
      reset: vi.fn(),
    });

    // Act
    const { result } = renderHook(() => useMasterItems(), { wrapper });

    // Assert
    expect(result.current.isLoading).toBe(false);
    expect(result.current.masterItems).toEqual(mockItems);
    expect(result.current.error).toBeNull();
  });

  it('should return an error state if the fetch fails', () => {
    // Arrange: Mock a failed data fetch.
    const mockError = new Error('Failed to fetch master items');
    mockedUseApiOnMount.mockReturnValue({ data: null, loading: false, error: mockError, isRefetching: false, reset: vi.fn() });

    // Act
    const { result } = renderHook(() => useMasterItems(), { wrapper });

    // Assert
    expect(result.current.isLoading).toBe(false);
    expect(result.current.masterItems).toEqual([]);
    expect(result.current.error).toBe('Failed to fetch master items');
  });
});