import { type CSSProperties, type ReactNode } from 'react';
import { useInfiniteQuery } from 'react-query';

import { type AxiosResponse } from 'axios';
import { useDebounce } from '@material-hu/hooks/useDebounce';
import List from '@material-hu/mui/List';
import ListSubheader from '@material-hu/mui/ListSubheader';
import { type SxProps, type Theme } from '@material-hu/mui/styles';

import useGeneralError from 'src/hooks/useGeneralError';
import { getUserList } from 'src/services/users';
import {
  type User,
  type UserDictionaryItem,
  type UserListResponse,
} from 'src/types/user';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getUsersForSectionList } from 'src/utils/userUtils';

import { peopleSearchKeys } from 'src/components/dashboard/people/queries';
import InfiniteList from 'src/components/list/InfiniteList';

import PeopleItem from './PeopleItem';

export type PeopleListProps = {
  queryKey?: (
    search: string,
    filterSelf?: boolean,
    notIncludingIds?: number[],
  ) => unknown[];
  getUsersList?: (
    search: string,
    page: number,
    limit: number,
    filterSelf?: boolean,
    notIncludingIds?: number[],
  ) => Promise<AxiosResponse<UserListResponse>>;
  limit?: number;
  listContainerStyle?: SxProps<Theme>;
  listSubHeaderStyle?: CSSProperties;
  select?: (users: User[]) => User[];
  multiple?: boolean;
  query?: string;
  handleSelect?: (user: User) => void;
  checks?: number[];
  renderUserCustom?: (user: User) => ReactNode;
  formTextField?: boolean;
  filterSelf?: boolean;
  notIncludingIds?: number[];
  onUpdateCountResult?: (count: number) => void;
  keepPreviousData?: boolean;
};

export const PeopleList = (props: PeopleListProps) => {
  const {
    queryKey = peopleSearchKeys.detail,
    getUsersList = getUserList,
    limit = 100,
    listContainerStyle = {},
    listSubHeaderStyle = {},
    select = (users: User[]) => users,
    multiple = false,
    query,
    handleSelect,
    checks,
    renderUserCustom = null,
    formTextField = false,
    onUpdateCountResult,
    filterSelf = true,
    notIncludingIds = [],
    keepPreviousData = false,
  } = props;

  const { t } = useLokaliseTranslation('people');
  const showGeneralError = useGeneralError();
  const debouncedQuery = useDebounce(query);

  const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteQuery(
      queryKey(debouncedQuery ?? '', filterSelf, notIncludingIds),
      ({ pageParam = 1 }) =>
        getUsersList(
          debouncedQuery ?? '',
          pageParam,
          limit,
          filterSelf,
          notIncludingIds,
        ),
      {
        cacheTime: 300 * (60 * 1000),
        keepPreviousData,
        getNextPageParam: (lastPage, pages) => {
          const { page, totalPages } = pages[pages.length - 1]?.data || {};

          return page < totalPages ? pages.length + 1 : undefined;
        },
        onError: err => showGeneralError(err, t('ERROR_LOADING_CONTACTS')),
        onSuccess: successData => {
          if (onUpdateCountResult) {
            onUpdateCountResult(successData.pages[0].data.count);
          }
        },
      },
    );

  const results = data?.pages.reduce<UserDictionaryItem[]>(
    (resultsAcc, page) =>
      getUsersForSectionList(select(page.data.items), resultsAcc),
    [],
  );

  return (
    <InfiniteList
      isSuccess={!!results}
      isLoading={isLoading}
      isEmpty={results?.length === 0}
      fetchNextPage={fetchNextPage}
      hasNextPage={hasNextPage}
      isFetchingNextPage={isFetchingNextPage}
      sx={{
        position: 'relative',
        zIndex: formTextField ? 2 : 0,
        overflow: 'auto',
        height: formTextField ? '300px' : '100%',
        ...listContainerStyle,
      }}
    >
      <List subheader={<li />}>
        {results?.map(item => (
          <li key={`section-${item.character}`}>
            <ul>
              <ListSubheader
                style={{
                  top: '-2px',
                  ...listSubHeaderStyle,
                }}
              >
                {item.character}
              </ListSubheader>
              {renderUserCustom
                ? item.users.map(renderUserCustom)
                : item.users.map(user => (
                    <PeopleItem
                      user={user}
                      key={`user-${user.id}`}
                      multiple={multiple}
                      onSelect={handleSelect}
                      checks={checks}
                    />
                  ))}
            </ul>
          </li>
        ))}
      </List>
    </InfiniteList>
  );
};

export default PeopleList;
