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

import { times } from 'lodash-es';
import { useDrawerV2 as useDrawer } from '@material-hu/hooks/useDrawerV2';
import Stack from '@material-hu/mui/Stack';

import FilterAccordion, {
  FilterAccordionSkeleton,
} from '@material-hu/components/composed-components/FilterAccordion';
import { SegmentationGroupType } from '@material-hu/components/composed-components/peopleExperience/types';

import { getSegmentationGroupsData } from '../../../../services';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { pxKeys } from '../../../../queries';
import SegmentFilterItems from '../../components/SegmentFilterItems';
import useFilterState from '../useFilterState';
import {
  type GroupMetadata,
  type SerializedFilterState,
} from '../useFilterState/types';

type UseFilterDrawerProps = {
  surveyId: number;
  appliedFilters: SerializedFilterState;
  onApply: () => void;
  onClear: () => void;
};

const useFilterDrawer = ({
  surveyId,
  appliedFilters,
  onApply,
  onClear,
}: UseFilterDrawerProps) => {
  const { t } = useLokaliseTranslation('people_experience');
  const [groupsMetadata, setGroupsMetadata] = useState<GroupMetadata[]>([]);

  const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery({
    queryKey: pxKeys.infiniteSegmentationGroups(surveyId),
    queryFn: ({ pageParam = 1 }) =>
      getSegmentationGroupsData({ surveyId, page: pageParam, limit: 10 }),
    getNextPageParam: lastPage =>
      lastPage.page === lastPage.totalPages ? undefined : lastPage.page + 1,
  });

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

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

  const allGroups = useMemo(() => {
    return data?.pages.flatMap(page => page.items) ?? [];
  }, [data]);

  const handleIndexItemsCountChange = useCallback(
    (groupId: number, count: number) => {
      setGroupsMetadata(prev =>
        prev.map(group =>
          group.id === groupId ? { ...group, indexCount: count } : group,
        ),
      );
    },
    [],
  );

  const handleIndexItemsChange = useCallback(
    (groupId: number, nextItems: { id: number; name: string }[]) => {
      setGroupsMetadata(prev =>
        prev.map(group =>
          group.id === groupId ? { ...group, indexItems: nextItems } : group,
        ),
      );
    },
    [],
  );

  const handleToggleItem = useCallback(
    (groupId: number, itemId: number, itemName: string, checked: boolean) => {
      filters.handlers.toggleItem(groupId, itemId, itemName);
      if (checked) {
        setGroupsMetadata(prev =>
          prev.map(group =>
            group.id === groupId
              ? {
                  ...group,
                  pickedItems: [
                    ...group.pickedItems,
                    { id: itemId, name: itemName },
                  ],
                }
              : group,
          ),
        );
      }
    },
    [],
  );

  const filters = useFilterState(groupsMetadata, appliedFilters);

  useEffect(() => {
    setGroupsMetadata(
      allGroups.map(group => ({
        id: group.id,
        displayName: group.name,
        indexCount: 0,
        indexItems: [],
        pickedItems: [],
      })),
    );

    allGroups.forEach(group => {
      if (
        group.type === SegmentationGroupType.AGE ||
        group.type === SegmentationGroupType.SENIORITY
      ) {
        filters.handlers.registerGroupType(group.id, group.type);
      }
    });
  }, [allGroups]);

  const drawer = useDrawer(({ closeDrawer }) => {
    return {
      title: t('filters'),
      onClose: () => {
        filters.dispatch({
          type: 'INITIALIZE_FILTERS',
          filters: appliedFilters,
        });
        closeDrawer();
      },
      children: (
        <Stack sx={{ gap: 2 }}>
          {isLoading &&
            times(5, index => <FilterAccordionSkeleton key={index} />)}
          {allGroups.map(item => {
            const isExpanded = filters.state.expandedGroups.has(item.id);
            const isSelectAll =
              filters.derived.getSelectAllState(item.id) === 'all';

            const previewItems = filters.derived
              .getGroupPreviewItems(item.id)
              .map(_item => _item.name);

            const previewItemsCount = isSelectAll
              ? filters.derived.getGroupTotalItems(item.id) -
                (filters.state.deselectedItems.get(item.id)?.size || 0)
              : previewItems.length;

            return (
              <FilterAccordion
                key={item.id}
                name={item.name}
                expanded={isExpanded}
                allItemsCount={previewItemsCount}
                previewItems={previewItems}
                getAndText={(left, right) => t('items_and', { left, right })}
                getMoreText={count => t('items_more', { count })}
                onChange={expanded =>
                  filters.handlers.setExpansion(item.id, expanded)
                }
                allChecked={isSelectAll}
              >
                <SegmentFilterItems
                  active={isExpanded}
                  surveyId={surveyId}
                  groupId={item.id}
                  groupType={item.type}
                  onSelectItem={handleToggleItem}
                  allChecked={filters.handlers.selectAll}
                  isItemSelected={filters.derived.isItemSelected}
                  getSelectAllState={filters.derived.getSelectAllState}
                  onIndexTotalCountChange={handleIndexItemsCountChange}
                  onIndexItemsChange={handleIndexItemsChange}
                />
              </FilterAccordion>
            );
          })}
          {hasNextPage && (
            <Stack
              ref={ref}
              sx={{ gap: 2 }}
            >
              {times(3, index => (
                <FilterAccordionSkeleton key={index} />
              ))}
            </Stack>
          )}
        </Stack>
      ),
      primaryButtonProps: {
        children: t('apply'),
        fullWidth: true,
        onClick: () => {
          onApply();
          closeDrawer();
        },
      },
      secondaryButtonProps: {
        children: t('clear_filters'),
        fullWidth: true,
        onClick: () => {
          onClear();
          closeDrawer();
        },
      },
    };
  });

  return { drawer, filters };
};

export default useFilterDrawer;
