import {
  Controller,
  FormProvider,
  useForm,
  useFormContext,
} from 'react-hook-form';

import { useDrawer } from '@material-hu/hooks/useDrawer';
import { IconZoomExclamation } from '@material-hu/icons/tabler';
import ListItemButton from '@material-hu/mui/ListItemButton';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuStateCard from '@material-hu/components/composed-components/StateCard';
import Alert from '@material-hu/components/design-system/Alert';
import HuCheckbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import FormSearch from '@material-hu/components/design-system/Inputs/Search/form';

import {
  UsersItemsOperation,
  useInfiniteUsersPublicSearch,
} from 'src/services/usersQueries';
import { addOrRemoveSet } from 'src/utils/arrayUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';

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

import SelectedUsersList from './components/SelectedUsersList';
import UserListItem from './components/UserListItem';
import { INDIVIDUAL_SELECTION_LIMIT } from './constants';
import { type FormEmployeesSelectorProps } from './types';

const FormEmployeesSelector = ({
  name,
  sx,
  allowSelectAll = true,
  segmentationGroupsIds,
  disabled,
  filterOperation = UsersItemsOperation.UNION,
  customAlertDescription,
  minimumSelectionCount = 0,
  disabledUserIds = [],
  deleteTooltip,
  maxSelection = INDIVIDUAL_SELECTION_LIMIT,
}: FormEmployeesSelectorProps) => {
  const { t } = useLokaliseTranslation('backoffice_only');
  const { control, watch, setValue } = useFormContext();
  const form = useForm({
    defaultValues: {
      search: '',
      segmentationGroupsIds: [],
      selected: [],
    },
  });
  const selected = watch(name, []);
  const selectedSet = new Set(selected);

  const { search } = form.watch();

  const isAtMinimum =
    selectedSet.size <= minimumSelectionCount && minimumSelectionCount > 0;
  const isAtMaximum = selectedSet.size >= maxSelection;

  const isUserDisabled = (userId: number) => {
    const isSelected = selectedSet.has(userId);

    if (disabled) return true;
    if (disabledUserIds?.includes(userId)) return true;
    if (isAtMaximum && !isSelected) return true;
    if (isAtMinimum && isSelected) return true;

    return false;
  };

  const { drawer: selectedUsersDrawer, showDrawer: showSelectedUsersDrawer } =
    useDrawer(
      SelectedUsersList,
      {
        title: t(
          'backoffice_only:form_employees_selector.form_employees_selector__selected_users',
        ),
        hasBackButton: true,
      },
      {
        disabled: disabled || isAtMinimum,
        deleteTooltip: disabled || isAtMinimum ? deleteTooltip : undefined,
        disabledUserIds,
        selected,
        showSelectedOnly: true,
        onRemove: userId => {
          const newSelected = addOrRemoveSet(selectedSet, userId);
          setValue(name, Array.from(newSelected), { shouldDirty: true });
        },
      },
    );

  const allUsersRequest = useInfiniteUsersPublicSearch({
    search,
    segmentationItemIds: segmentationGroupsIds
      ? new Array(segmentationGroupsIds)
      : null,
    itemIdFilterOperation: filterOperation,
    limit: 50,
  });

  const allUsers = allUsersRequest?.data?.pages.flatMap(
    page => page.data.items,
  );
  const allUsersIdsSet = new Set(allUsers?.map(user => user.id));

  const allUsersSelected =
    selectedSet.intersection(allUsersIdsSet).size === allUsersIdsSet.size;

  const usersForSelect = allUsersRequest?.data?.pages
    .flatMap(page => page.data.items)
    .map(user => user.id);

  const onSelectAll = () => {
    if (allUsersSelected) {
      setValue(name, [], { shouldDirty: true });
    } else if (selectedSet.size) {
      setValue(name, usersForSelect, { shouldDirty: true });
    } else if (!selectedSet.size) {
      setValue(name, usersForSelect, { shouldDirty: true });
    }
  };

  return (
    <Controller
      control={control}
      name={name}
      render={() => (
        <FormProvider {...form}>
          <Stack sx={{ gap: 1, flex: 1, overflow: 'hidden', ...sx }}>
            <FormSearch
              name="search"
              inputProps={{ disabled, sx: { flex: 0 } }}
            />

            {!allUsers?.length &&
              !allUsersRequest?.isLoading &&
              (!!search || !!segmentationGroupsIds?.length) && (
                <HuStateCard
                  Icon={IconZoomExclamation}
                  title={t(
                    'backoffice_only:form_employees_selector.form_employees_selector__no_search_results_title',
                  )}
                  description={t(
                    'backoffice_only:form_employees_selector.form_employees_selector__no_search_results_description',
                  )}
                  sx={{ border: 'none' }}
                />
              )}

            <InfiniteList
              isEmpty={!allUsers?.length}
              isSuccess={!!allUsersRequest.isSuccess}
              isLoading={allUsersRequest.isLoading}
              fetchNextPage={allUsersRequest.fetchNextPage}
              isFetchingNextPage={allUsersRequest.isFetchingNextPage}
              hasNextPage={allUsersRequest.hasNextPage}
              sx={{ flex: 1, overflow: 'auto' }}
            >
              {allowSelectAll && (
                <ListItemButton
                  onClick={onSelectAll}
                  disabled={disabled}
                  sx={{ p: 2, borderRadius: 1, gap: 1, mb: 1 }}
                >
                  <HuCheckbox
                    checked={allUsersSelected}
                    disabled={
                      allUsersRequest.isFetching ||
                      !allUsers?.length ||
                      disabled
                    }
                  />
                  <Typography variant="globalS">
                    {t(
                      'backoffice_only:form_employees_selector.form_employees_selector__select_all',
                    )}
                  </Typography>
                </ListItemButton>
              )}
              {allUsers?.map(user => (
                <UserListItem
                  key={user.id}
                  id={user.id}
                  checked={selectedSet?.has(user.id)}
                  profilePicture={user.profilePicture || undefined}
                  displayName={[user.firstName, user.lastName].join(' ')}
                  disabled={isUserDisabled(user.id)}
                  onSelect={userId => {
                    const newSelected = addOrRemoveSet(selectedSet, userId);
                    setValue(name, Array.from(newSelected), {
                      shouldDirty: true,
                    });
                  }}
                  sx={{ flex: 0 }}
                />
              ))}
            </InfiniteList>

            <Stack
              sx={{
                borderTop: theme =>
                  `1px solid ${theme.palette.new.border.neutral.default}`,
                zIndex: 1,
                flex: 0,
              }}
            >
              <Alert
                severity={isAtMaximum || isAtMinimum ? 'warning' : 'info'}
                title={
                  selectedSet.size === 0
                    ? t(
                        'backoffice_only:form_employees_selector.form_employees_selector__no_selected_users',
                      )
                    : t(
                        'backoffice_only:form_employees_selector.form_employees_selector__user_reach',
                        {
                          count: selectedSet.size,
                        },
                      )
                }
                description={
                  customAlertDescription ||
                  (selectedSet.size >= maxSelection
                    ? t(
                        'backoffice_only:form_employees_selector.form_employees_selector__limit_selection_warning',
                        {
                          limit: maxSelection,
                        },
                      )
                    : t(
                        'backoffice_only:form_employees_selector.form_employees_selector__limit_selection',
                        {
                          limit: maxSelection,
                        },
                      ))
                }
                action={
                  selectedSet?.size
                    ? {
                        onClick: () => showSelectedUsersDrawer(),
                        text: t(
                          'backoffice_only:form_employees_selector.form_employees_selector__see_user_reach',
                        ),
                      }
                    : undefined
                }
                sx={{
                  '& .MuiButtonBase-root': {
                    minWidth: '144px',
                  },
                }}
              />
            </Stack>
          </Stack>
          {selectedUsersDrawer}
        </FormProvider>
      )}
    />
  );
};

export default FormEmployeesSelector;
