// src/hooks/useShoppingLists.tsx
import { useState, useCallback, useEffect, useMemo } from 'react';
import { useAuth } from '../hooks/useAuth';
import { useUserData } from '../hooks/useUserData';
import { useApi } from './useApi';
import * as apiClient from '../services/apiClient';
import type { ShoppingList, ShoppingListItem } from '../types';

/**
 * A custom hook to manage all state and logic related to shopping lists.
 * It encapsulates API calls and state updates for creating, deleting, and modifying lists and their items.
 */
const useShoppingListsHook = () => {
  const { userProfile } = useAuth();
  // We get the lists and the global setter from the DataContext.
  const { shoppingLists, setShoppingLists } = useUserData();

  const [activeListId, setActiveListId] = useState<number | null>(null);

  // API hooks for shopping list operations
  const {
    execute: createListApi,
    error: createError,
    loading: isCreatingList,
  } = useApi<ShoppingList, [string]>((name) => apiClient.createShoppingList(name));
  const {
    execute: deleteListApi,
    error: deleteError,
    loading: isDeletingList,
  } = useApi<null, [number]>((listId) => apiClient.deleteShoppingList(listId));
  const {
    execute: addItemApi,
    error: addItemError,
    loading: isAddingItem,
  } = useApi<ShoppingListItem, [number, { masterItemId?: number; customItemName?: string }]>(
    (listId, item) => apiClient.addShoppingListItem(listId, item),
  );
  const {
    execute: updateItemApi,
    error: updateItemError,
    loading: isUpdatingItem,
  } = useApi<ShoppingListItem, [number, Partial<ShoppingListItem>]>((itemId, updates) =>
    apiClient.updateShoppingListItem(itemId, updates),
  );
  const {
    execute: removeItemApi,
    error: removeItemError,
    loading: isRemovingItem,
  } = useApi<null, [number]>((itemId) => apiClient.removeShoppingListItem(itemId));

  // Consolidate errors from all API hooks into a single displayable error.
  const error = useMemo(() => {
    const firstError =
      createError || deleteError || addItemError || updateItemError || removeItemError;
    return firstError ? firstError.message : null;
  }, [createError, deleteError, addItemError, updateItemError, removeItemError]);

  // Effect to select the first list as active when lists are loaded or the user changes.
  useEffect(() => {
    // Check if the currently active list still exists in the shoppingLists array.
    const activeListExists = shoppingLists.some((l) => l.shopping_list_id === activeListId);

    // If the user is logged in and there are lists...
    if (userProfile && shoppingLists.length > 0) {
      // ...but no list is active, or the active one was deleted, select the first available list.
      if (!activeListExists) {
        setActiveListId(shoppingLists[0].shopping_list_id);
      }
    } else if (activeListId !== null) {
      // If there's no user or no lists, ensure no list is active.
      setActiveListId(null);
    }
  }, [shoppingLists, userProfile]); // This effect should NOT depend on activeListId to prevent re-selection loops.

  const createList = useCallback(
    async (name: string) => {
      if (!userProfile) return;
      try {
        const newList = await createListApi(name);
        if (newList) {
          setShoppingLists((prev) => [...prev, newList]);
        }
      } catch (e) {
        // The useApi hook handles setting the error state.
        // We catch the error here to prevent unhandled promise rejections and add logging.
        console.error('useShoppingLists: Failed to create list.', e);
      }
    },
    [userProfile, setShoppingLists, createListApi],
  );

  const deleteList = useCallback(
    async (listId: number) => {
      if (!userProfile) return;
      try {
        const result = await deleteListApi(listId);
        // A successful DELETE will have a null result from useApi (for 204 No Content)
        if (result === null) {
          setShoppingLists((prevLists) => prevLists.filter((l) => l.shopping_list_id !== listId));
        }
      } catch (e) {
        console.error('useShoppingLists: Failed to delete list.', e);
      }
    },
    [userProfile, setShoppingLists, deleteListApi],
  );

  const addItemToList = useCallback(
    async (listId: number, item: { masterItemId?: number; customItemName?: string }) => {
      if (!userProfile) return;

      // Find the target list first to check for duplicates *before* the API call.
      const targetList = shoppingLists.find((l) => l.shopping_list_id === listId);
      if (!targetList) {
        console.error(`useShoppingLists: List with ID ${listId} not found.`);
        return; // Or throw an error
      }

      // Prevent adding a duplicate master item.
      if (item.masterItemId) {
        const itemExists = targetList.items.some((i) => i.master_item_id === item.masterItemId);
        if (itemExists) {
          // Optionally, we could show a toast notification here.
          console.log(
            `useShoppingLists: Item with master ID ${item.masterItemId} already in list.`,
          );
          return; // Exit without calling the API.
        }
      }

      try {
        const newItem = await addItemApi(listId, item);
        if (newItem) {
          setShoppingLists((prevLists) =>
            prevLists.map((list) => {
              if (list.shopping_list_id === listId) {
                // The duplicate check is now handled above, so we can just add the item.
                return { ...list, items: [...list.items, newItem] };
              }
              return list;
            }),
          );
        }
      } catch (e) {
        console.error('useShoppingLists: Failed to add item.', e);
      }
    },
    [userProfile, shoppingLists, setShoppingLists, addItemApi],
  );

  const updateItemInList = useCallback(
    async (itemId: number, updates: Partial<ShoppingListItem>) => {
      if (!userProfile || !activeListId) return;
      try {
        const updatedItem = await updateItemApi(itemId, updates);
        if (updatedItem) {
          setShoppingLists((prevLists) =>
            prevLists.map((list) => {
              if (list.shopping_list_id === activeListId) {
                return {
                  ...list,
                  items: list.items.map((i) =>
                    i.shopping_list_item_id === itemId ? updatedItem : i,
                  ),
                };
              }
              return list;
            }),
          );
        }
      } catch (e) {
        console.error('useShoppingLists: Failed to update item.', e);
      }
    },
    [userProfile, activeListId, setShoppingLists, updateItemApi],
  );

  const removeItemFromList = useCallback(
    async (itemId: number) => {
      if (!userProfile || !activeListId) return;
      try {
        const result = await removeItemApi(itemId);
        if (result === null) {
          setShoppingLists((prevLists) =>
            prevLists.map((list) => {
              if (list.shopping_list_id === activeListId) {
                return {
                  ...list,
                  items: list.items.filter((i) => i.shopping_list_item_id !== itemId),
                };
              }
              return list;
            }),
          );
        }
      } catch (e) {
        console.error('useShoppingLists: Failed to remove item.', e);
      }
    },
    [userProfile, activeListId, setShoppingLists, removeItemApi],
  );

  return {
    shoppingLists,
    activeListId,
    setActiveListId,
    createList,
    deleteList,
    addItemToList,
    updateItemInList,
    removeItemFromList,
    isCreatingList,
    isDeletingList,
    isAddingItem,
    isUpdatingItem,
    isRemovingItem,
    error,
  };
};

export { useShoppingListsHook as useShoppingLists };
