import { useEffect, useMemo, useState } from 'react';
import { useInView } from 'react-intersection-observer';
import { InfiniteData, useInfiniteQuery, useQuery } from 'react-query';

import { AxiosResponse } from 'axios';
import { useDebounce } from '@material-hu/hooks/useDebounce';

import FilterAccordionContent from '@material-hu/components/composed-components/FilterAccordionContent';

import Spinner from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import { getSegmentationItems } from '../../../../services';
import { FilterOptionResponse } from '../../../../types';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { PaginatedResponse } from 'src/utils/pagination';

import { pxKeys } from '../../../../queries';

import { SegmentFilterItemProps } from './types';

const SegmentFilterItems = ({
  surveyId,
  groupId,
  groupType,
  onSelectItem,
  allChecked: onSelectAll,
  isItemSelected,
  getSelectAllState,
  onIndexTotalCountChange,
  onIndexItemsChange,
  active = false,
}: SegmentFilterItemProps) => {
  const { t } = useLokaliseTranslation('people_experience');
  const [searchText, setSearchText] = useState('');
  const debouncedSearchText = useDebounce(searchText, 300);

  const { data: indexData } = useQuery({
    queryKey: pxKeys.segmentationItems({
      surveyId,
      groupId,
      searchText: '',
    }),
    enabled: false,
    select: (
      response: InfiniteData<
        AxiosResponse<PaginatedResponse<FilterOptionResponse>, any>
      >,
    ) => {
      return response.pages;
    },
  });

  const indexItems = useMemo(
    () => indexData?.flatMap(page => page.data.items) ?? [],
    [indexData],
  );

  const { data, isLoading, isPreviousData, hasNextPage, fetchNextPage } =
    useInfiniteQuery(
      pxKeys.segmentationItems({
        surveyId,
        groupId,
        searchText: debouncedSearchText,
      }),
      ({ pageParam = 1 }) =>
        getSegmentationItems({
          surveyId,
          groupId,
          limit: 10,
          page: pageParam,
          type: groupType,
          searchText: debouncedSearchText,
        }),
      {
        getNextPageParam: lastPage =>
          lastPage.data.page === lastPage.data.totalPages
            ? undefined
            : lastPage.data.page + 1,
        keepPreviousData: true,
        enabled: active,
        refetchOnMount: false,
      },
    );

  const { ref, inView } = useInView({
    threshold: 0,
  });

  useEffect(() => {
    if (inView) {
      fetchNextPage();
    }
  }, [inView, fetchNextPage]);

  const selectAllState = getSelectAllState(groupId);

  // All the items that the group has.
  const allItems = useMemo(
    () => data?.pages.flatMap(page => page.data.items) ?? [],
    [data],
  );

  // Update total count for this group. All the items that the group has.
  useEffect(() => {
    onIndexTotalCountChange(groupId, indexData?.[0]?.data?.count ?? 0);
  }, [indexData, onIndexTotalCountChange, groupId]);

  // Update the list of selected/preview items for this group when the list of all items changes.
  useEffect(() => {
    onIndexItemsChange(groupId, indexItems);
  }, [indexItems, onIndexItemsChange, groupId]);

  if (isLoading) {
    return <Spinner />;
  }

  return (
    <FilterAccordionContent
      items={allItems}
      slotProps={{ root: { sx: { opacity: isPreviousData ? 0.5 : 1 } } }}
      onChangeSearch={setSearchText}
      searchValue={searchText}
      getItemCheckboxProps={item => ({
        label: item.name,
        checked: isItemSelected(groupId, item.id),
        onChange: (_, checked) =>
          onSelectItem(groupId, item.id, item.name, checked),
      })}
      allCheckboxProps={{
        label: t('select_all'),
        onChange: () => onSelectAll(groupId),
        indeterminate: selectAllState === 'indeterminate',
        checked: selectAllState === 'all',
        disabled: searchText.length > 0,
      }}
      hasMoreItems={hasNextPage}
      loadMoreTriggerRef={ref}
      noResultsTitle={t('no_results')}
      noResultsDescription={t('no_results_description')}
      searchLabel={t('search')}
      loading={isLoading}
    />
  );
};

export default SegmentFilterItems;
