import { useState, useCallback, useMemo } from 'react';

export interface UseBatchSelectionResult<T = any> {
  selectedIds: Set<number | string>;
  selectedItems: T[];
  isSelected: (id: number | string) => boolean;
  isAllSelected: boolean;
  isSomeSelected: boolean;
  toggle: (id: number | string) => void;
  select: (id: number | string) => void;
  deselect: (id: number | string) => void;
  selectAll: () => void;
  deselectAll: () => void;
  toggleAll: () => void;
  setItems: (items: T[]) => void;
  getSelectedIds: () => (number | string)[];
  getSelectedItems: () => T[];
}

/**
 * Hook for managing batch selection in tables/lists
 * Handles select all, toggle, and individual selections
 * 
 * @example
 * const selection = useBatchSelection(articles, 'id');
 * <Checkbox checked={selection.isSelected(article.id)} onChange={() => selection.toggle(article.id)} />
 * <button disabled={selection.selectedIds.size === 0} onClick={handleBatchDelete}>
 *   Delete Selected ({selection.selectedIds.size})
 * </button>
 */
export function useBatchSelection<T = any>(
  items: T[] = [],
  idField: keyof T = 'id' as keyof T
): UseBatchSelectionResult<T> {
  const [selectedIds, setSelectedIds] = useState<Set<number | string>>(new Set());
  const [currentItems, setCurrentItems] = useState<T[]>(items);

  const setItems = useCallback((newItems: T[]) => {
    setCurrentItems(newItems);
    // Clear selection when items change
    setSelectedIds(new Set());
  }, []);

  const isSelected = useCallback(
    (id: number | string) => selectedIds.has(id),
    [selectedIds]
  );

  const toggle = useCallback((id: number | string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  }, []);

  const select = useCallback((id: number | string) => {
    setSelectedIds((prev) => new Set(prev).add(id));
  }, []);

  const deselect = useCallback((id: number | string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      next.delete(id);
      return next;
    });
  }, []);

  const selectAll = useCallback(() => {
    const allIds = currentItems.map((item) => item[idField] as number | string);
    setSelectedIds(new Set(allIds));
  }, [currentItems, idField]);

  const deselectAll = useCallback(() => {
    setSelectedIds(new Set());
  }, []);

  const toggleAll = useCallback(() => {
    if (selectedIds.size === currentItems.length && currentItems.length > 0) {
      deselectAll();
    } else {
      selectAll();
    }
  }, [selectedIds.size, currentItems.length, selectAll, deselectAll]);

  const selectedItems = useMemo(() => {
    return currentItems.filter((item) => selectedIds.has(item[idField] as number | string));
  }, [currentItems, selectedIds, idField]);

  const isAllSelected = useMemo(() => {
    return currentItems.length > 0 && selectedIds.size === currentItems.length;
  }, [currentItems.length, selectedIds.size]);

  const isSomeSelected = useMemo(() => {
    return selectedIds.size > 0 && selectedIds.size < currentItems.length;
  }, [selectedIds.size, currentItems.length]);

  const getSelectedIds = useCallback(() => {
    return Array.from(selectedIds);
  }, [selectedIds]);

  const getSelectedItems = useCallback(() => {
    return selectedItems;
  }, [selectedItems]);

  return {
    selectedIds,
    selectedItems,
    isSelected,
    isAllSelected,
    isSomeSelected,
    toggle,
    select,
    deselect,
    selectAll,
    deselectAll,
    toggleAll,
    setItems,
    getSelectedIds,
    getSelectedItems,
  };
}
