// src/hooks/useShoppingLists.test.tsx
import { renderHook, act, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, type Mock, test } from 'vitest';
import { useShoppingLists } from './useShoppingLists';
import { useApi } from './useApi';
import { useAuth } from '../hooks/useAuth';
import { useUserData } from '../hooks/useUserData';
import * as apiClient from '../services/apiClient';
import {
  createMockShoppingList,
  createMockShoppingListItem,
  createMockUserProfile,
  createMockUser,
} from '../tests/utils/mockFactories';
import React from 'react';
import type { ShoppingList, User } from '../types'; // Import ShoppingList and User types

// Define a type for the mock return value of useApi to ensure type safety in tests
type MockApiResult = {
  execute: Mock;
  error: Error | null;
  loading: boolean;
  isRefetching: boolean;
  data: any;
  reset: Mock;
};

// Mock the hooks that useShoppingLists depends on
vi.mock('./useApi');
vi.mock('../hooks/useAuth');
vi.mock('../hooks/useUserData');

// The apiClient is globally mocked in our test setup, so we just need to cast it
const mockedUseApi = vi.mocked(useApi);
const mockedUseAuth = vi.mocked(useAuth);
const mockedUseUserData = vi.mocked(useUserData);

// Create a mock User object by extracting it from a mock UserProfile
const mockUserProfile = createMockUserProfile({
  user: createMockUser({ user_id: 'user-123', email: 'test@example.com' }),
});

describe('useShoppingLists Hook', () => {
  // Create a mock setter function that we can spy on
  const mockSetShoppingLists = vi.fn() as unknown as React.Dispatch<
    React.SetStateAction<ShoppingList[]>
  >;

  // Create mock execute functions for each API operation
  const mockCreateListApi = vi.fn();
  const mockDeleteListApi = vi.fn();
  const mockAddItemApi = vi.fn();
  const mockUpdateItemApi = vi.fn();
  const mockRemoveItemApi = vi.fn();

  const defaultApiMocks: MockApiResult[] = [
    {
      execute: mockCreateListApi,
      error: null,
      loading: false,
      isRefetching: false,
      data: null,
      reset: vi.fn(),
    },
    {
      execute: mockDeleteListApi,
      error: null,
      loading: false,
      isRefetching: false,
      data: null,
      reset: vi.fn(),
    },
    {
      execute: mockAddItemApi,
      error: null,
      loading: false,
      isRefetching: false,
      data: null,
      reset: vi.fn(),
    },
    {
      execute: mockUpdateItemApi,
      error: null,
      loading: false,
      isRefetching: false,
      data: null,
      reset: vi.fn(),
    },
    {
      execute: mockRemoveItemApi,
      error: null,
      loading: false,
      isRefetching: false,
      data: null,
      reset: vi.fn(),
    },
  ];

  // Helper function to set up the useApi mock for a specific test run
  const setupApiMocks = (mocks: MockApiResult[] = defaultApiMocks) => {
    let callCount = 0;
    mockedUseApi.mockImplementation(() => {
      const mock = mocks[callCount % mocks.length];
      callCount++;
      return mock;
    });
  };

  beforeEach(() => {
    // Reset all mocks before each test to ensure isolation
    vi.clearAllMocks();

    // Mock useApi to return a sequence of successful API configurations by default
    setupApiMocks();

    mockedUseAuth.mockReturnValue({
      userProfile: mockUserProfile,
      authStatus: 'AUTHENTICATED',
      isLoading: false,
      login: vi.fn(),
      logout: vi.fn(),
      updateProfile: vi.fn(),
    });

    mockedUseUserData.mockReturnValue({
      shoppingLists: [],
      setShoppingLists: mockSetShoppingLists,
      watchedItems: [],
      setWatchedItems: vi.fn(),
      isLoading: false,
      error: null,
    });
  });

  it('should initialize with no active list when there are no lists', () => {
    const { result } = renderHook(() => useShoppingLists());

    expect(result.current.shoppingLists).toEqual([]);
    expect(result.current.activeListId).toBeNull();
  });

  it('should set the first list as active on initial load if lists exist', async () => {
    const mockLists = [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', user_id: 'user-123' }),
      createMockShoppingList({ shopping_list_id: 2, name: 'Hardware Store', user_id: 'user-123' }),
    ];

    mockedUseUserData.mockReturnValue({
      shoppingLists: mockLists,
      setShoppingLists: mockSetShoppingLists,
      watchedItems: [],
      setWatchedItems: vi.fn(),
      isLoading: false,
      error: null,
    });

    const { result } = renderHook(() => useShoppingLists());

    await waitFor(() => expect(result.current.activeListId).toBe(1));
  });

  it('should not set an active list if the user is not authenticated', () => {
    mockedUseAuth.mockReturnValue({
      userProfile: null,
      authStatus: 'SIGNED_OUT',
      isLoading: false,
      login: vi.fn(),
      logout: vi.fn(),
      updateProfile: vi.fn(),
    });
    const mockLists = [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', user_id: 'user-123' }),
    ];
    mockedUseUserData.mockReturnValue({
      shoppingLists: mockLists,
      setShoppingLists: mockSetShoppingLists,
      watchedItems: [],
      setWatchedItems: vi.fn(),
      isLoading: false,
      error: null,
    });

    const { result } = renderHook(() => useShoppingLists());

    expect(result.current.activeListId).toBeNull();
  });

  it('should set activeListId to null when lists become empty', async () => {
    const mockLists = [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', user_id: 'user-123' }),
    ];

    // Initial render with a list
    mockedUseUserData.mockReturnValue({
      shoppingLists: mockLists,
      setShoppingLists: mockSetShoppingLists,
      watchedItems: [],
      setWatchedItems: vi.fn(),
      isLoading: false,
      error: null,
    });

    const { result, rerender } = renderHook(() => useShoppingLists());

    await waitFor(() => expect(result.current.activeListId).toBe(1));

    // Rerender with empty lists
    mockedUseUserData.mockReturnValue({
      shoppingLists: [],
      setShoppingLists: mockSetShoppingLists,
      watchedItems: [],
      setWatchedItems: vi.fn(),
      isLoading: false,
      error: null,
    });
    rerender();

    // The effect should update the activeListId to null
    await waitFor(() => expect(result.current.activeListId).toBeNull());
  });

  it('should expose loading states for API operations', () => {
    // Mock useApi to return loading: true for each specific operation in sequence
    mockedUseApi
      .mockReturnValueOnce({ ...defaultApiMocks[0], loading: true }) // create
      .mockReturnValueOnce({ ...defaultApiMocks[1], loading: true }) // delete
      .mockReturnValueOnce({ ...defaultApiMocks[2], loading: true }) // add item
      .mockReturnValueOnce({ ...defaultApiMocks[3], loading: true }) // update item
      .mockReturnValueOnce({ ...defaultApiMocks[4], loading: true }); // remove item

    const { result } = renderHook(() => useShoppingLists());

    expect(result.current.isCreatingList).toBe(true);
    expect(result.current.isDeletingList).toBe(true);
    expect(result.current.isAddingItem).toBe(true);
    expect(result.current.isUpdatingItem).toBe(true);
    expect(result.current.isRemovingItem).toBe(true);
  });

  it('should configure useApi with the correct apiClient methods', async () => {
    renderHook(() => useShoppingLists());

    // useApi is called 5 times in the hook in this order:
    // 1. createList, 2. deleteList, 3. addItem, 4. updateItem, 5. removeItem
    const createListApiFn = mockedUseApi.mock.calls[0][0];
    const deleteListApiFn = mockedUseApi.mock.calls[1][0];
    const addItemApiFn = mockedUseApi.mock.calls[2][0];
    const updateItemApiFn = mockedUseApi.mock.calls[3][0];
    const removeItemApiFn = mockedUseApi.mock.calls[4][0];

    await createListApiFn('New List');
    expect(apiClient.createShoppingList).toHaveBeenCalledWith('New List');

    await deleteListApiFn(1);
    expect(apiClient.deleteShoppingList).toHaveBeenCalledWith(1);

    await addItemApiFn(1, { customItemName: 'Item' });
    expect(apiClient.addShoppingListItem).toHaveBeenCalledWith(1, { customItemName: 'Item' });

    await updateItemApiFn(1, { is_purchased: true });
    expect(apiClient.updateShoppingListItem).toHaveBeenCalledWith(1, { is_purchased: true });

    await removeItemApiFn(1);
    expect(apiClient.removeShoppingListItem).toHaveBeenCalledWith(1);
  });

  describe('createList', () => {
    it('should call the API and update state on successful creation', async () => {
      const newList = createMockShoppingList({
        shopping_list_id: 99,
        name: 'New List',
        user_id: 'user-123',
      });
      let currentLists: ShoppingList[] = [];

      // Mock the implementation of the setter to simulate a real state update.
      // This will cause the hook to re-render with the new list.
      (mockSetShoppingLists as Mock).mockImplementation(
        (updater: React.SetStateAction<ShoppingList[]>) => {
          currentLists = typeof updater === 'function' ? updater(currentLists) : updater;
        },
      );

      // The hook will now see the updated `currentLists` on re-render.
      mockedUseUserData.mockImplementation(() => ({
        shoppingLists: currentLists,
        setShoppingLists: mockSetShoppingLists,
        watchedItems: [],
        setWatchedItems: vi.fn(),
        isLoading: false,
        error: null,
      }));

      mockCreateListApi.mockResolvedValue(newList);

      const { result } = renderHook(() => useShoppingLists());

      // `act` ensures that all state updates from the hook are processed before assertions are made
      await act(async () => {
        await result.current.createList('New List');
      });

      expect(mockCreateListApi).toHaveBeenCalledWith('New List');
      expect(currentLists).toEqual([newList]);
    });
  });

  describe('deleteList', () => {
    // Use a function to get a fresh copy for each test run
    const getMockLists = () => [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', user_id: 'user-123' }),
      createMockShoppingList({ shopping_list_id: 2, name: 'Hardware Store', user_id: 'user-123' }),
    ];

    let currentLists: ShoppingList[] = [];

    beforeEach(() => {
      // Isolate state for each test in this describe block
      currentLists = getMockLists();
      (mockSetShoppingLists as Mock).mockImplementation((updater) => {
        currentLists = typeof updater === 'function' ? updater(currentLists) : updater;
      });
      mockedUseUserData.mockImplementation(() => ({
        shoppingLists: currentLists,
        setShoppingLists: mockSetShoppingLists,
        watchedItems: [],
        setWatchedItems: vi.fn(),
        isLoading: false,
        error: null,
      }));
    });

    it('should call the API and update state on successful deletion', async () => {
      console.log('TEST: should call the API and update state on successful deletion');
      mockDeleteListApi.mockResolvedValue(null); // Successful delete returns null

      const { result, rerender } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial lists count:', currentLists.length);
      await act(async () => {
        console.log('  LOG: Deleting list with ID 1.');
        await result.current.deleteList(1);
        rerender();
      });

      await waitFor(() => expect(mockDeleteListApi).toHaveBeenCalledWith(1));
      console.log('  LOG: Final lists count:', currentLists.length);
      // Check that the global state setter was called with the correctly filtered list
      expect(currentLists).toHaveLength(1);
      expect(currentLists[0].shopping_list_id).toBe(2);
      console.log('  LOG: SUCCESS! State was updated correctly.');
    });

    it('should update activeListId if the active list is deleted', async () => {
      console.log('TEST: should update activeListId if the active list is deleted');
      mockDeleteListApi.mockResolvedValue(null);

      // Render the hook and wait for the initial effect to set activeListId
      const { result, rerender } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial ActiveListId:', result.current.activeListId);
      await waitFor(() => expect(result.current.activeListId).toBe(1));
      console.log('  LOG: Waited for ActiveListId to be 1.');

      await act(async () => {
        console.log('  LOG: Deleting active list (ID 1).');
        await result.current.deleteList(1);
        rerender();
      });

      console.log('  LOG: Deletion complete. Checking for new ActiveListId...');
      // After deletion, the hook should select the next available list as active
      await waitFor(() => expect(result.current.activeListId).toBe(2));
      console.log('  LOG: SUCCESS! ActiveListId updated to 2.');
    });

    it('should not change activeListId if a non-active list is deleted', async () => {
      console.log('TEST: should not change activeListId if a non-active list is deleted');
      mockDeleteListApi.mockResolvedValue(null);
      const { result, rerender } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial ActiveListId:', result.current.activeListId);
      await waitFor(() => expect(result.current.activeListId).toBe(1)); // Initial active is 1
      console.log('  LOG: Waited for ActiveListId to be 1.');

      await act(async () => {
        console.log('  LOG: Deleting non-active list (ID 2).');
        await result.current.deleteList(2); // Delete list 2
        rerender();
      });

      await waitFor(() => expect(mockDeleteListApi).toHaveBeenCalledWith(2));
      console.log('  LOG: Final lists count:', currentLists.length);
      expect(currentLists).toHaveLength(1);
      expect(currentLists[0].shopping_list_id).toBe(1); // Only list 1 remains
      console.log('  LOG: Final ActiveListId:', result.current.activeListId);
      expect(result.current.activeListId).toBe(1); // Active list ID should not change
      console.log('  LOG: SUCCESS! ActiveListId remains 1.');
    });

    it('should set activeListId to null when the last list is deleted', async () => {
      console.log('TEST: should set activeListId to null when the last list is deleted');
      const singleList = [
        createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', user_id: 'user-123' }),
      ];
      // Override the state for this specific test
      currentLists = singleList;
      mockDeleteListApi.mockResolvedValue(null);

      const { result, rerender } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial render. ActiveListId:', result.current.activeListId);
      await waitFor(() => expect(result.current.activeListId).toBe(1));
      console.log('  LOG: ActiveListId successfully set to 1.');
      await act(async () => {
        console.log('  LOG: Calling deleteList(1).');
        await result.current.deleteList(1);
        console.log('  LOG: deleteList(1) finished. Rerendering component with updated lists.');
        rerender();
      });
      console.log('  LOG: act/rerender complete. Final ActiveListId:', result.current.activeListId);
      await waitFor(() => expect(result.current.activeListId).toBeNull());
      console.log('  LOG: SUCCESS! ActiveListId is null as expected.');
    });
  });

  describe('addItemToList', () => {
    let currentLists: ShoppingList[] = [];
    const getMockLists = () => [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', user_id: 'user-123' }),
    ];

    beforeEach(() => {
      currentLists = getMockLists();
      (mockSetShoppingLists as Mock).mockImplementation((updater) => {
        currentLists = typeof updater === 'function' ? updater(currentLists) : updater;
      });
      mockedUseUserData.mockImplementation(() => ({
        shoppingLists: currentLists,
        setShoppingLists: mockSetShoppingLists,
        watchedItems: [],
        setWatchedItems: vi.fn(),
        isLoading: false,
        error: null,
      }));
    });

    it('should call API and add item to the correct list', async () => {
      const newItem = createMockShoppingListItem({
        shopping_list_item_id: 101,
        shopping_list_id: 1,
        custom_item_name: 'Milk',
      });
      mockAddItemApi.mockResolvedValue(newItem);

      const { result, rerender } = renderHook(() => useShoppingLists());

      await act(async () => {
        await result.current.addItemToList(1, { customItemName: 'Milk' });
        rerender();
      });

      expect(mockAddItemApi).toHaveBeenCalledWith(1, { customItemName: 'Milk' });
      expect(currentLists[0].items).toHaveLength(1);
      expect(currentLists[0].items[0]).toEqual(newItem);
    });

    it('should not call the API if a duplicate item (by master_item_id) is added', async () => {
      console.log('TEST: should not call the API if a duplicate item (by master_item_id) is added');
      const existingItem = createMockShoppingListItem({
        shopping_list_item_id: 100,
        shopping_list_id: 1,
        master_item_id: 5,
        custom_item_name: 'Milk',
      });
      // Override state for this specific test
      currentLists = [
        createMockShoppingList({
          shopping_list_id: 1,
          name: 'Groceries',
          user_id: 'user-123',
          items: [existingItem],
        }),
      ];

      const { result, rerender } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial item count:', currentLists[0].items.length);
      await act(async () => {
        console.log('  LOG: Attempting to add duplicate masterItemId: 5');
        await result.current.addItemToList(1, { masterItemId: 5 });
        rerender();
      });

      // The API should not have been called because the duplicate was caught client-side.
      expect(mockAddItemApi).not.toHaveBeenCalled();

      console.log('  LOG: Final item count:', currentLists[0].items.length);
      expect(currentLists[0].items).toHaveLength(1); // Length should remain 1
      console.log('  LOG: SUCCESS! Duplicate was not added and API was not called.');
    });

    it('should log an error and not call the API if the listId does not exist', async () => {
      const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
      const { result } = renderHook(() => useShoppingLists());

      await act(async () => {
        // Call with a non-existent list ID (mock lists have IDs 1 and 2)
        await result.current.addItemToList(999, { customItemName: 'Wont be added' });
      });

      // The API should not have been called because the list was not found.
      expect(mockAddItemApi).not.toHaveBeenCalled();
      expect(consoleErrorSpy).toHaveBeenCalledWith('useShoppingLists: List with ID 999 not found.');

      consoleErrorSpy.mockRestore();
    });
  });

  describe('updateItemInList', () => {
    const initialItem = createMockShoppingListItem({
      shopping_list_item_id: 101,
      shopping_list_id: 1,
      custom_item_name: 'Milk',
      is_purchased: false,
      quantity: 1,
    });
    const multiLists = [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', items: [initialItem] }),
      createMockShoppingList({ shopping_list_id: 2, name: 'Other' }),
    ];

    beforeEach(() => {
      mockedUseUserData.mockReturnValue({
        shoppingLists: multiLists,
        setShoppingLists: mockSetShoppingLists,
        watchedItems: [],
        setWatchedItems: vi.fn(),
        isLoading: false,
        error: null,
      });
    });

    it('should call API and update the correct item, leaving other lists unchanged', async () => {
      const updatedItem = { ...initialItem, is_purchased: true };
      mockUpdateItemApi.mockResolvedValue(updatedItem);

      const { result } = renderHook(() => useShoppingLists());
      act(() => {
        result.current.setActiveListId(1);
      }); // Set active list

      await act(async () => {
        await result.current.updateItemInList(101, { is_purchased: true });
      });

      expect(mockUpdateItemApi).toHaveBeenCalledWith(101, { is_purchased: true });
      const updater = (mockSetShoppingLists as Mock).mock.calls[0][0];
      const newState = updater(multiLists);
      expect(newState[0].items[0].is_purchased).toBe(true);
      expect(newState[1]).toBe(multiLists[1]); // Verify other list is unchanged
    });

    it('should not call update API if no list is active', async () => {
      console.log('TEST: should not call update API if no list is active');
      const { result } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial render. ActiveListId:', result.current.activeListId);

      // Wait for the initial effect to set the active list
      await waitFor(() => expect(result.current.activeListId).toBe(1));
      console.log('  LOG: Initial active list is 1.');

      act(() => {
        result.current.setActiveListId(null);
      }); // Ensure no active list
      console.log(
        '  LOG: Manually set activeListId to null. Current value:',
        result.current.activeListId,
      );
      await act(async () => {
        console.log('  LOG: Calling updateItemInList while activeListId is null.');
        await result.current.updateItemInList(101, { is_purchased: true });
      });
      expect(mockUpdateItemApi).not.toHaveBeenCalled();
      console.log('  LOG: SUCCESS! mockUpdateItemApi was not called.');
    });
  });

  describe('removeItemFromList', () => {
    const initialItem = createMockShoppingListItem({
      shopping_list_item_id: 101,
      shopping_list_id: 1,
      custom_item_name: 'Milk',
    });
    const multiLists = [
      createMockShoppingList({ shopping_list_id: 1, name: 'Groceries', items: [initialItem] }),
      createMockShoppingList({ shopping_list_id: 2, name: 'Other' }),
    ];

    beforeEach(() => {
      mockedUseUserData.mockReturnValue({
        shoppingLists: multiLists,
        setShoppingLists: mockSetShoppingLists,
        watchedItems: [],
        setWatchedItems: vi.fn(),
        isLoading: false,
        error: null,
      });
    });

    it('should call API and remove item from the active list, leaving other lists unchanged', async () => {
      mockRemoveItemApi.mockResolvedValue(null);
      const { result } = renderHook(() => useShoppingLists());
      act(() => {
        result.current.setActiveListId(1);
      });

      await act(async () => {
        await result.current.removeItemFromList(101);
      });

      expect(mockRemoveItemApi).toHaveBeenCalledWith(101);
      const updater = (mockSetShoppingLists as Mock).mock.calls[0][0];
      const newState = updater(multiLists);
      expect(newState[0].items).toHaveLength(0);
      expect(newState[1]).toBe(multiLists[1]); // Verify other list is unchanged
    });

    it('should not call remove API if no list is active', async () => {
      console.log('TEST: should not call remove API if no list is active');
      const { result } = renderHook(() => useShoppingLists());
      console.log('  LOG: Initial render. ActiveListId:', result.current.activeListId);

      // Wait for the initial effect to set the active list
      await waitFor(() => expect(result.current.activeListId).toBe(1));
      console.log('  LOG: Initial active list is 1.');

      act(() => {
        result.current.setActiveListId(null);
      }); // Ensure no active list
      console.log(
        '  LOG: Manually set activeListId to null. Current value:',
        result.current.activeListId,
      );
      await act(async () => {
        console.log('  LOG: Calling removeItemFromList while activeListId is null.');
        await result.current.removeItemFromList(101);
      });
      expect(mockRemoveItemApi).not.toHaveBeenCalled();
      console.log('  LOG: SUCCESS! mockRemoveItemApi was not called.');
    });
  });

  describe('API Error Handling', () => {
    test.each([
      {
        name: 'createList',
        action: (hook: any) => hook.createList('New List'),
        apiMock: mockCreateListApi,
        mockIndex: 0,
        errorMessage: 'API Failed',
      },
      {
        name: 'deleteList',
        action: (hook: any) => hook.deleteList(1),
        apiMock: mockDeleteListApi,
        mockIndex: 1,
        errorMessage: 'Deletion failed',
      },
      {
        name: 'addItemToList',
        action: (hook: any) => hook.addItemToList(1, { customItemName: 'Milk' }),
        apiMock: mockAddItemApi,
        mockIndex: 2,
        errorMessage: 'Failed to add item',
      },
      {
        name: 'updateItemInList',
        action: (hook: any) => hook.updateItemInList(101, { is_purchased: true }),
        apiMock: mockUpdateItemApi,
        mockIndex: 3,
        errorMessage: 'Update failed',
      },
      {
        name: 'removeItemFromList',
        action: (hook: any) => hook.removeItemFromList(101),
        apiMock: mockRemoveItemApi,
        mockIndex: 4,
        errorMessage: 'Removal failed',
      },
    ])(
      'should set an error for $name if the API call fails',
      async ({ action, apiMock, mockIndex, errorMessage }) => {
        // Setup a default list so activeListId is set automatically
        const mockList = createMockShoppingList({ shopping_list_id: 1, name: 'List 1' });
        mockedUseUserData.mockReturnValue({
          shoppingLists: [mockList],
          setShoppingLists: mockSetShoppingLists,
          watchedItems: [],
          setWatchedItems: vi.fn(),
          isLoading: false,
          error: null,
        });

        const apiMocksWithError = [...defaultApiMocks];
        apiMocksWithError[mockIndex] = {
          ...apiMocksWithError[mockIndex],
          error: new Error(errorMessage),
        };
        setupApiMocks(apiMocksWithError);
        apiMock.mockRejectedValue(new Error(errorMessage));

        // Spy on console.error to ensure the catch block is executed for logging
        const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});

        const { result } = renderHook(() => useShoppingLists());

        // Wait for the effect to set the active list ID
        await waitFor(() => expect(result.current.activeListId).toBe(1));

        await act(async () => {
          await action(result.current);
        });

        await waitFor(() => {
          expect(result.current.error).toBe(errorMessage);
          // Verify that our custom logging within the catch block was called
          expect(consoleErrorSpy).toHaveBeenCalled();
        });

        consoleErrorSpy.mockRestore();
      },
    );
  });

  it('should not perform actions if user is not authenticated', async () => {
    mockedUseAuth.mockReturnValue({
      userProfile: null,
      authStatus: 'SIGNED_OUT',
      isLoading: false,
      login: vi.fn(),
      logout: vi.fn(),
      updateProfile: vi.fn(),
    });

    const { result } = renderHook(() => useShoppingLists());

    await act(async () => {
      await result.current.createList('Should not work');
    });

    expect(mockCreateListApi).not.toHaveBeenCalled();
  });
});
