import { useCallback, useState } from 'react';
import {
  CollectionState,
  Filter,
  FiltersMap,
  OptionalFiltersMap,
} from '@wix/bex-core';
import {
  CollectionConfig,
  CollectionConfigWithConditionals,
  CursorFetchDataFn,
  OffsetFetchDataFn,
  useCreateCollection,
} from '@wix/bex-core/react';

type FiltersConfig<F extends FiltersMap> = F extends OptionalFiltersMap
  ? { filters?: {} }
  : { filters: F };

type PaginationModeConfig<T, F extends FiltersMap> =
  | {
      paginationMode?: 'offset';
      fetchData: OffsetFetchDataFn<T, F>;
    }
  | {
      paginationMode: 'cursor';
      fetchData: CursorFetchDataFn<T, F>;
    };

export type FilterCollectionConfig<T, F extends FiltersMap> = Omit<
  CollectionConfig<T, F>,
  | 'itemKey'
  | 'itemName'
  | 'filters'
  | 'paginationMode'
  | 'fetchData'
  | 'fetchErrorMessage'
> &
  FiltersConfig<F> &
  PaginationModeConfig<T, F>;

export type FilterCollectionFactory = <T, F extends FiltersMap = FiltersMap>(
  filter: Filter<T[]>,
  config: FilterCollectionConfig<T, F>,
) => CollectionState<T, F>;

export function useCreateFilterCollection(): FilterCollectionFactory {
  const createCollection = useCreateCollection();

  return useCallback(
    <T, F extends FiltersMap = FiltersMap>(
      filter: Filter<T[]>,
      config: FilterCollectionConfig<T, F>,
    ) => {
      return createCollection<T, F>({
        itemKey: filter.itemKey,
        itemName: filter.itemName,
        ...config,
        fetchErrorMessage: () => null,
        filters: config.filters ?? {},
      } as CollectionConfigWithConditionals<T, F>);
    },
    [],
  );
}

export function useFilterCollection<
  T,
  F extends FiltersMap = OptionalFiltersMap,
>(
  filter: Filter<T[]>,
  config: FilterCollectionConfig<T, F>,
): CollectionState<T, F> {
  const createFilterCollection = useCreateFilterCollection();

  const [collection] = useState(() =>
    createFilterCollection<T, F>(filter, {
      ...config,
      queryOptions: {
        refetchOnMount: false,
        retryOnMount: false,
      },
    }),
  );

  return collection;
}
