import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import PerfectScrollbar from 'react-perfect-scrollbar';

import SkeletonList from '@composed-components/audience/IndividualSelection/components/SkeletonList';
import InfiniteListLoader from '@composed-components/InfiniteListLoader';
import SelectableListItem from '@composed-components/SelectableListItem';
import UserAvatar from '@composed-components/UserAvatar';
import CardContainer from '@design-system/CardContainer';
import Search from '@design-system/Inputs/Search';
import List from '@design-system/List';
import StateCard from '@design-system/StateCard';
import { useDebounce } from '@hooks/useDebounce';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import { appearFromBottom } from '@utils/animations';

import { type UserAutoCompleteProps } from './types';

const styles = {
  borderRadius: 1,
  animation: `${appearFromBottom} 125ms ease-in-out backwards`,
};

const RESULT_LIST_HEIGHT = '320px';

const UserAutoComplete = ({
  onChange,
  onSearch,
  searchValue = '',
  slotProps,
  usersQuery,
  usersQueryDataParser,
  selectionLimit,
  value = new Set(),
  idKey = 'id',
  sx,
  infiniteScroll,
  onLoadMore,
}: UserAutoCompleteProps) => {
  const scrollContainerRef = useRef<HTMLDivElement | null>(null);
  const psContainerRef = useRef<HTMLElement | null>(null);
  const [internalSearch, setInternalSearch] = useState(searchValue ?? '');
  const debouncedSearch = useDebounce(internalSearch, 300);

  useEffect(() => {
    onSearch?.(debouncedSearch);
    if (psContainerRef.current) {
      psContainerRef.current.scrollTop = 0;
    }
  }, [debouncedSearch, onSearch]);

  useEffect(() => {
    setInternalSearch(searchValue ?? '');
  }, [searchValue]);

  const parsedData = useMemo(
    () => usersQueryDataParser(usersQuery.data),
    [usersQuery.data, usersQueryDataParser],
  );

  const handleUserSelect = useCallback(
    (userId: string | number) => {
      const newSet = new Set([...value]);
      if (newSet.has(userId)) {
        newSet.delete(userId);
      } else {
        newSet.add(userId);
      }
      onChange?.(newSet);
    },
    [value, onChange],
  );

  const disableSearch = !parsedData?.length && !internalSearch;
  const canSelectMore = selectionLimit ? value?.size < selectionLimit : true;

  const handlePsContainerRef = useCallback((el: HTMLElement) => {
    psContainerRef.current = el;
    if (el) {
      el.style.overscrollBehavior = 'contain';
    }
  }, []);
  const isEmpty =
    !parsedData?.length && !usersQuery.isLoading && !usersQuery.isFetching;

  const hasInfiniteScroll = infiniteScroll && !!onLoadMore;
  const showLoadingNextPage = hasInfiniteScroll && usersQuery.isFetching;
  const triggerOnLoadMore = hasInfiniteScroll && !usersQuery.isFetching;

  const showResults = !!parsedData?.length && !usersQuery.isLoading;
  const listContainerHeight = isEmpty ? '100%' : RESULT_LIST_HEIGHT;

  const handleYReachEnd = useCallback(() => {
    if (triggerOnLoadMore) {
      onLoadMore();
    }
  }, [triggerOnLoadMore, onLoadMore]);

  return (
    <Stack
      sx={{
        height: '100%',
        gap: 1,
        ...sx,
      }}
    >
      <Stack sx={{ flexDirection: 'row', alignItems: 'center' }}>
        {slotProps?.search && (
          <Search
            {...slotProps.search}
            value={internalSearch}
            onChange={setInternalSearch}
            disabled={disableSearch}
          />
        )}
      </Stack>
      <CardContainer
        padding={0}
        sx={{
          backgroundColor: theme =>
            theme.palette.new.background.elements.default,
          borderRadius: styles.borderRadius,
          width: '100%',
          position: 'relative',
          '& .ps__rail-y': {
            zIndex: 1,
          },
        }}
      >
        <Box
          ref={scrollContainerRef}
          sx={{
            height: listContainerHeight,
          }}
        >
          <PerfectScrollbar
            style={{ height: '100%' }}
            options={{ suppressScrollX: true }}
            containerRef={handlePsContainerRef}
            onYReachEnd={handleYReachEnd}
          >
            {usersQuery.isLoading && <SkeletonList sx={{ p: 2 }} />}
            {isEmpty && (
              <StateCard
                title={slotProps?.emptyStateCard?.title ?? ''}
                description={slotProps?.emptyStateCard?.description ?? ''}
                slotProps={{
                  ...slotProps?.emptyStateCard?.slotProps,
                  card: {
                    sx: {
                      border: 'none',
                      animation: `${appearFromBottom} 125ms ease-in-out backwards`,
                    },
                  },
                }}
              />
            )}
            {showResults && (
              <List
                sx={{
                  p: 0,
                  display: 'flex',
                  flexDirection: 'column',
                  zIndex: 0,
                  m: 2,
                }}
              >
                {parsedData.map(user => {
                  const userId = user[idKey as keyof typeof user] as
                    | string
                    | number;
                  const isSelected = value?.has(userId);
                  return (
                    <SelectableListItem
                      key={String(userId)}
                      id={String(userId)}
                      disabled={!isSelected && !canSelectMore}
                      selected={isSelected}
                      sx={styles}
                      onSelect={() => handleUserSelect(userId)}
                    >
                      <UserAvatar
                        user={user}
                        {...slotProps?.userAvatar}
                      />
                    </SelectableListItem>
                  );
                })}
                {showLoadingNextPage && (
                  <InfiniteListLoader
                    sx={{ alignSelf: 'center', mx: 'auto', mt: 2 }}
                    loading={usersQuery.isFetching}
                    onLoadMore={onLoadMore}
                    containerRef={scrollContainerRef}
                  />
                )}
              </List>
            )}
          </PerfectScrollbar>
        </Box>
      </CardContainer>
    </Stack>
  );
};

export default UserAutoComplete;
