import { type FC, useCallback, useEffect, useRef, useState } from 'react';
import { useInfiniteQuery } from 'react-query';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import { IconCheck } from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import { alpha } from '@material-hu/mui/styles';

import HuSearch from '@material-hu/components/design-system/Inputs/Search';
import HuList from '@material-hu/components/design-system/List';
import HuListItem from '@material-hu/components/design-system/List/components/ListItem';
import HuSpinner from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import HuTitle from '@material-hu/components/design-system/Title';

import { useAuth } from 'src/contexts/JWTContext';
import { getAgentCandidates } from 'src/pages/dashboard/serviceManagement/services';
import { type UserTask } from 'src/pages/dashboard/serviceManagement/types';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getFullName, getInitials } from 'src/utils/userUtils';

import { serviceManagementKeys } from '../queries';
import { getUserDisplayName } from '../utils';

type Props = {
  currentAssignedAgent?: UserTask;
  onSelect: (agent: UserTask) => void;
  serviceItemId: string;
};

const MAX_AGENTS_SHOWN = 5;
const AGENT_LIST_ITEM_HEIGHT = 40;

const CandidateAgentAutocomplete: FC<Props> = ({
  serviceItemId,
  onSelect,
  currentAssignedAgent,
}) => {
  const [query, setQuery] = useState('');
  const { t } = useLokaliseTranslation('service_management');
  const { user: loggedUser } = useAuth();

  const listRef = useRef<HTMLDivElement | null>(null);
  const loadMoreRef = useRef<HTMLDivElement | null>(null);

  const debouncedQuery = useDebounce(query);

  const agentsQuery = useInfiniteQuery(
    serviceManagementKeys.agents.candidates(serviceItemId, debouncedQuery),
    ({ pageParam = 1 }) =>
      getAgentCandidates(serviceItemId, {
        search: debouncedQuery,
        page: pageParam,
      }),
    {
      getNextPageParam: lastPage => {
        const nextPage =
          lastPage?.data?.page < lastPage?.data?.totalPages
            ? lastPage?.data?.page + 1
            : undefined;
        return nextPage;
      },
      keepPreviousData: true,
      staleTime: 5 * 60 * 1000,
      enabled: !!serviceItemId,
    },
  );

  const handleViewMore = useCallback(() => {
    if (agentsQuery.hasNextPage && !agentsQuery.isFetchingNextPage) {
      agentsQuery.fetchNextPage();
    }
  }, [
    agentsQuery.hasNextPage,
    agentsQuery.isFetchingNextPage,
    agentsQuery.fetchNextPage,
  ]);

  useEffect(() => {
    const observer = new IntersectionObserver(
      entries => {
        if (entries[0].isIntersecting) {
          handleViewMore();
        }
      },
      {
        root: listRef.current,
        rootMargin: '0px',
        threshold: 1.0,
      },
    );

    if (loadMoreRef.current) {
      observer.observe(loadMoreRef.current);
    }

    return () => {
      observer.disconnect();
    };
  }, [handleViewMore]);

  const agents =
    agentsQuery.data?.pages?.flatMap(page => page.data.items) || [];

  const loading =
    agentsQuery.isLoading ||
    agentsQuery.isFetchingNextPage ||
    agentsQuery.isFetching;

  const noResults = agents.length === 0 && !loading;

  return (
    <Stack sx={{ p: 1, borderRadius: 1.5, gap: 0.5 }}>
      <HuSearch
        fullWidth
        value={query}
        variant="custom"
        onChange={q => setQuery(q)}
        placeholder={t('search')}
      />
      <Stack ref={listRef}>
        <HuList
          sx={{
            p: 0,
            m: 0,
            maxHeight: `${MAX_AGENTS_SHOWN * AGENT_LIST_ITEM_HEIGHT}px`,
            overflowY: 'auto',
            opacity: agentsQuery.isPreviousData ? 0.5 : 1,
            borderRadius: 1,
          }}
        >
          {agents.map(agent => {
            const isCurrentAgent = currentAssignedAgent?.id === agent.id;
            return (
              <HuListItem
                sx={{
                  ...(isCurrentAgent && {
                    backgroundColor: ({ palette }) =>
                      alpha(palette.primary.main, 0.08),
                  }),
                }}
                key={agent.id}
                onClick={() => {
                  if (!isCurrentAgent) {
                    onSelect(agent as UserTask);
                  }
                }}
                avatar={{
                  src: agent.profilePicture ?? undefined,
                  text: getInitials(getFullName(agent)),
                }}
                text={{
                  title: getUserDisplayName(agent as UserTask, loggedUser!, t),
                }}
                sideContent={isCurrentAgent ? <IconCheck /> : undefined}
              />
            );
          })}
          <div ref={loadMoreRef} />
        </HuList>
      </Stack>
      {!loading && noResults && (
        <HuTitle
          centered
          variant="S"
          title={t('agent_autocomplete_no_results_title')}
          description={t('agent_autocomplete_no_results_description')}
        />
      )}
      {agentsQuery.isError && (
        <HuTitle
          centered
          variant="S"
          title={t('agent_autocomplete_error_title')}
          description={t('agent_autocomplete_error_description')}
        />
      )}
      {loading && (
        <Stack sx={{ width: 1 }}>
          <HuSpinner
            sx={{ mx: 'auto', my: 0.5 }}
            size={20}
          />
        </Stack>
      )}
    </Stack>
  );
};

export default CandidateAgentAutocomplete;
