import { type Dispatch, type FC, type SetStateAction } from 'react';
import { FormProvider } from 'react-hook-form';
import { useInfiniteQuery } from 'react-query';

import { flatMap, mapValues } from 'lodash-es';
import { useDebounce } from '@material-hu/hooks/useDebounce';
import { useDrawer } from '@material-hu/hooks/useDrawer';
import { IconSearch } from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';

import HuCheckbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import HuFormInputClassic from '@material-hu/components/design-system/Inputs/Classic/form';
import HuListItem from '@material-hu/components/design-system/List/components/ListItem';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';

import usePermissions from 'src/hooks/usePermissions';
import { getInvitableUsers } from 'src/services/events';
import { type Event } from 'src/types/events';
import { addOrRemove } from 'src/utils/arrays';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getListItemsLength, getNextPage } from 'src/utils/pagination';
import { UserPermissions } from 'src/utils/permissions';
import { getFullName } from 'src/utils/userUtils';

import { InfiniteList } from 'src/components/list';

import { eventsKeys } from '../queries';
import { userInitials } from '../utils';

import EmptyState from './EmptyState';
import { FiltersegmentationButton } from './FilterSegmentationButton';
import SegmentationsData from './SegmentationsData';
import ListSkeleton from './skeleton/ListSkeleton';

type Props = {
  event: Event;
  form;
  uninvitedCount: number;
  segmentationItems: number[];
  setSegmentationItems: Dispatch<SetStateAction<number[]>>;
};

export const InvitePeople: FC<Props> = ({
  event,
  form,
  uninvitedCount,
  segmentationItems,
  setSegmentationItems,
}) => {
  const { enqueueSnackbar } = useHuSnackbar();
  const { hasAll: canSegmentate } = usePermissions([
    UserPermissions.CAN_SEGMENTATE,
  ]);

  const { t } = useLokaliseTranslation('events');

  const [selectAllUsers, excludedUserIds, search, segmentationItemIds] =
    form.watch([
      'selectAllUsers',
      'excludedUserIds',
      'search',
      'segmentationItemIds',
    ]);
  const debouncedSearch = useDebounce(search);

  const allUsers = useInfiniteQuery(
    eventsKeys.eventUsers(event.id, debouncedSearch, segmentationItems),
    ({ pageParam = 1 }) =>
      getInvitableUsers(
        event.id,
        debouncedSearch,
        pageParam,
        segmentationItems,
      ),
    {
      getNextPageParam: (_, pages) =>
        getNextPage(getListItemsLength(pages), 100, pages),
      cacheTime: 0,
    },
  );

  const isEmpty = allUsers.data?.pages && !allUsers.data?.pages[0]?.data?.count;

  const isEventPublic = !event?.groupId;

  const onHandleFiltersClick = () => {
    enqueueSnackbar({
      title: t('FILTERS_APPLIED_CORRECTLY'),
      variant: 'info',
    });
    setSegmentationItems(flatMap(segmentationItemIds));
    closeGroupsSegmentationDrawer();
  };

  const cleanSegmentationFilters = () => {
    form.setValue(
      'segmentationItemIds',
      mapValues(segmentationItemIds, () => []),
    );
  };

  const onClose = () => {
    form.reset();
    closeGroupsSegmentationDrawer();
    setSegmentationItems([]);
  };

  const disableCleanFilter = flatMap(segmentationItemIds).length === 0;
  const {
    showDrawer: showGroupsSegmentationDrawer,
    closeDrawer: closeGroupsSegmentationDrawer,
    drawer: groupsSegmentationDrawer,
  } = useDrawer(
    SegmentationsData,
    {
      title: t('FILTER_BY'),
      primaryButtonProps: {
        children: t('APPLY_FILTERS'),
        onClick: onHandleFiltersClick,
      },
      secondaryButtonProps: {
        children: t('CLEAN_FILTERS'),
        onClick: cleanSegmentationFilters,
        disabled: disableCleanFilter,
      },
      onClose: onClose,
    },
    { event, form },
  );

  return (
    <FormProvider {...form}>
      {groupsSegmentationDrawer}
      <Stack
        sx={{
          gap: 3,
        }}
      >
        <Stack sx={{ flexDirection: 'row', gap: 1 }}>
          {!allUsers.isLoading && (
            <>
              <HuFormInputClassic
                name="search"
                inputProps={{
                  placeholder: t('SEARCH_PEOPLE'),
                  startAdornment: <IconSearch size={24} />,
                  hasCounter: false,
                }}
              />
              {isEventPublic && canSegmentate && (
                <FiltersegmentationButton
                  count={segmentationItems.length}
                  showDrawer={showGroupsSegmentationDrawer}
                />
              )}
            </>
          )}
        </Stack>
        {isEmpty && (
          <EmptyState
            sx={{ border: 'none' }}
            titleProps={{
              title: t('NO_RESULTS_FOUND'),
              description: t('TRY_OTHER_TERMS'),
            }}
          />
        )}
        {!search && !isEmpty && !allUsers.isLoading && (
          <HuCheckbox
            label={
              flatMap(segmentationItemIds).length > 0
                ? t('SELECT_FILTERED')
                : t('SELECT_ALL')
            }
            indeterminate={excludedUserIds.length > 0}
            checked={selectAllUsers}
            disabled={uninvitedCount === 0}
            onChange={() => {
              form.setValue('selectAllUsers', !selectAllUsers);
              form.setValue('excludedUserIds', []);
            }}
          />
        )}
        <InfiniteList
          isSuccess={!!allUsers.data}
          isLoading={allUsers.isLoading}
          isEmpty={isEmpty}
          fetchNextPage={allUsers.fetchNextPage}
          hasNextPage={allUsers.hasNextPage}
          isFetchingNextPage={allUsers.isFetchingNextPage}
          showNoResultsMessage={false}
          customLoader={<ListSkeleton />}
        >
          {allUsers.data?.pages
            .flatMap(page => page.data.items)
            .map(user => {
              const profilePicture = user.profilePicture;
              const isChecked =
                selectAllUsers !== excludedUserIds.includes(user.id);
              return (
                <Stack
                  key={user.id}
                  sx={{ flexDirection: 'row', alignItems: 'center' }}
                >
                  <HuCheckbox
                    label=""
                    checked={user.isInvited || isChecked}
                    disabled={user.isInvited}
                    onChange={() => {
                      form.setValue(
                        'excludedUserIds',
                        addOrRemove(excludedUserIds, user.id),
                      );
                    }}
                  />

                  <HuListItem
                    avatar={{
                      src: profilePicture,
                      text: !profilePicture && userInitials(user),
                      color: 'primary',
                    }}
                    text={{ title: getFullName(user) }}
                  />
                </Stack>
              );
            })}
        </InfiniteList>
      </Stack>
    </FormProvider>
  );
};

export default InvitePeople;
