import { type FC, Fragment, useMemo } from 'react';
import { useFormContext } from 'react-hook-form';
import { type TFunction, Trans } from 'react-i18next';
import { useInView } from 'react-intersection-observer';
import { type UseInfiniteQueryResult } from 'react-query';

import { IconTrash } from '@material-hu/icons/tabler';
import Divider from '@material-hu/mui/Divider';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuCardContainer from '@material-hu/components/design-system/CardContainer';
import HuCheckbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import HuDrawer from '@material-hu/components/design-system/Drawer';
import HuFormAutocomplete from '@material-hu/components/design-system/Inputs/Autocomplete/form';
import HuCircularProgress from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import StateCard from '@material-hu/components/design-system/StateCard';
import HuTooltip from '@material-hu/components/design-system/Tooltip';

import { useLokaliseTranslation } from 'src/utils/i18n';

export type EntityItem = {
  id: string;
  name: string;
  [key: string]: any;
};

type Props = {
  open: boolean;
  onClose: () => void;
  onCancel: () => void;
  onConfirm: () => void;
  loading?: boolean;
  formFieldName: string;
  userEntities: EntityItem[];
  title: string;
  labelText: string;
  searchPlaceholder: string;
  emptyStateTitle: string;
  emptyStateDescription: string;
  helperText: string;
  canRemoveEntity: (entityId: string) => boolean;
  tooltipTitle: string;
  tooltipDescription: string;
  queryResult: UseInfiniteQueryResult<any>;
  resetSearch: () => void;
  onSearchChange: (value: string) => void;
  hasSearch: boolean;
};

const GenericEntitySelectionDrawer: FC<Props> = ({
  open,
  onClose,
  onCancel,
  onConfirm,
  loading: loadingAction = false,
  formFieldName,
  userEntities,
  title,
  labelText,
  searchPlaceholder,
  emptyStateTitle,
  emptyStateDescription,
  hasSearch,
  helperText,
  canRemoveEntity,
  tooltipTitle,
  tooltipDescription,
  queryResult,
  resetSearch,
  onSearchChange,
}) => {
  const { t } = useLokaliseTranslation(['service_management', 'general']);
  const { watch, setValue } = useFormContext();

  const [loadMoreRef] = useInView({
    onChange: inViewState => {
      if (inViewState && hasNextPage && !isFetching) {
        fetchNextPage();
      }
    },
    threshold: 0.5,
  });

  const { data, isLoading, isFetching, fetchNextPage, hasNextPage, isError } =
    queryResult;

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

  const handleRemove = (entityId: string) => {
    const newEntities = selectedEntities.filter(
      entity => entity.value !== entityId,
    );
    setValue(formFieldName, newEntities);
  };

  const selectedEntities: { value: string; label: string }[] =
    watch(formFieldName);

  // Disable the "Update" button if there are no changes made to the user's entities
  const isMutationDisabled = useMemo(() => {
    if (userEntities.length !== selectedEntities?.length) return false;

    return userEntities.every(entity =>
      selectedEntities.some(selected => selected.value === entity.id),
    );
  }, [userEntities, selectedEntities]);

  const showEmptyEntityCard =
    !isLoading &&
    !isFetching &&
    !isError &&
    !hasSearch &&
    entities?.length === 0;

  return (
    <HuDrawer
      open={open}
      onClose={onClose}
      title={title}
      primaryButtonProps={{
        onClick: () => {
          onConfirm();
          resetSearch();
        },
        children: t('general:update'),
        disabled: isMutationDisabled,
        loading: loadingAction,
        fullWidth: true,
      }}
      secondaryButtonProps={{
        onClick: onCancel,
        children: t('general:cancel'),
        fullWidth: true,
        disabled: loadingAction,
      }}
    >
      {isLoading && <HuCircularProgress />}
      {showEmptyEntityCard && (
        <StateCard
          title={emptyStateTitle}
          description={
            <Trans
              t={t as TFunction}
              i18nKey={emptyStateDescription}
              components={{ b: <b /> }}
            />
          }
          slotProps={{
            card: {
              sx: {
                border: 'unset',
                backgroundColor: theme =>
                  theme.palette.new.background.elements.grey,
              },
            },
          }}
        />
      )}
      {!showEmptyEntityCard && (
        <Stack sx={{ width: 1, gap: 2 }}>
          <Typography variant="globalS">{helperText}</Typography>
          <Stack
            sx={{
              backgroundColor: theme =>
                theme.palette.new.background.layout.default,
              borderRadius: 2,
              p: 2,
              width: 1,
              gap: 2,
            }}
          >
            <HuFormAutocomplete
              key={`autocomplete-${open}`}
              name={formFieldName}
              options={entities.map(entity => ({
                label: entity.name,
                value: entity.id,
              }))}
              autocompleteProps={{
                label: labelText,
                multiple: true,
                loading: isLoading || isFetching,
                hasMoreOptions: hasNextPage,
                onLoadMore: fetchNextPage,
                loadingText: `${t('general:loading')}...`,
                isServerFiltered: true,
                clearIcon: false,
                placeholder: searchPlaceholder,
                onInputChange: (_, value) => {
                  onSearchChange(value);
                },
                renderTags: () => null,
                renderOption: ({ key, ...props }, option, state) => {
                  const { index } = state;
                  const isDisabled = !canRemoveEntity(option.value);
                  const isSelected = selectedEntities?.some(
                    entity => entity.value === option.value,
                  );

                  const content = [
                    <Stack
                      key={`option-${option.value}-${isSelected}`}
                      {...props}
                      component="li"
                      onClick={isDisabled ? undefined : props?.onClick}
                      sx={{
                        flexDirection: 'row',
                        alignItems: 'center',
                        ...(isDisabled && {
                          bgcolor: 'transparent !important',
                          cursor: 'default !important',
                          '&:hover': {
                            bgcolor: 'transparent !important',
                          },
                        }),
                      }}
                    >
                      <Stack
                        sx={{
                          flexDirection: 'row',
                          alignItems: 'center',
                          justifyContent: 'space-between',
                          p: 1,
                          gap: 1,
                        }}
                      >
                        <HuCheckbox
                          key={`checkbox-${option.value}-${isSelected}`}
                          disabled={isDisabled}
                          checked={isSelected}
                        />
                        <Typography
                          variant="globalS"
                          sx={{
                            color: theme =>
                              isDisabled
                                ? theme.palette.new.text.neutral.disabled
                                : theme.palette.new.text.neutral.default,
                          }}
                        >
                          {option.label}
                        </Typography>
                      </Stack>
                    </Stack>,
                  ];

                  // Add loading indicator when reaching the end of the list
                  const optionsLen = entities.length - 1;
                  const isLoadMoreVisible = index === optionsLen && hasNextPage;

                  if (isLoadMoreVisible) {
                    content.push(
                      <Stack
                        key="load-more"
                        component="li"
                        ref={loadMoreRef}
                        sx={{
                          width: '100%',
                          display: 'flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          py: 1,
                        }}
                      >
                        <HuCircularProgress size={24} />
                      </Stack>,
                    );
                  }

                  return content;
                },
              }}
            />
            {selectedEntities?.length > 0 && (
              <HuCardContainer
                fullWidth
                padding={16}
              >
                {selectedEntities.map((entity, index) => (
                  <Fragment key={entity.value}>
                    <Stack
                      sx={{
                        flexDirection: 'row',
                        alignItems: 'center',
                        justifyContent: 'space-between',
                      }}
                    >
                      <Typography
                        variant="globalS"
                        fontWeight="fontWeightSemiBold"
                      >
                        {entity.label}
                      </Typography>
                      <HuTooltip
                        title={tooltipTitle}
                        description={tooltipDescription}
                        disableTooltip={canRemoveEntity(entity.value)}
                        direction="bottom"
                        delay={500}
                      >
                        <span>
                          <IconButton
                            aria-label={t('general:delete')}
                            onClick={() => handleRemove(entity.value)}
                            disabled={!canRemoveEntity(entity.value)}
                            sx={{
                              color: theme =>
                                theme.palette.new.text.neutral.default,
                            }}
                          >
                            <IconTrash />
                          </IconButton>
                        </span>
                      </HuTooltip>
                    </Stack>
                    {index < selectedEntities.length - 1 && (
                      <Divider sx={{ my: 1 }} />
                    )}
                  </Fragment>
                ))}
              </HuCardContainer>
            )}
          </Stack>
        </Stack>
      )}
    </HuDrawer>
  );
};

export default GenericEntitySelectionDrawer;
