import { useCallback } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { type UseInfiniteQueryResult } from 'react-query';

import { type AxiosResponse } from 'axios';
import Stack from '@material-hu/mui/Stack';

import HuSearch from '@material-hu/components/design-system/Inputs/Search';

import { type User } from 'src/types/user';
import { type PaginatedResponse } from 'src/utils/pagination';

import InfiniteList from 'src/components/list/InfiniteList';

import PeopleItemList from '../../components/inputs/PeopleItemList';

export type SelectionMode = 'single' | 'multiple';

type Props<T> = {
  fieldName?: string;
  selectionMode?: SelectionMode;
  search: string;
  onSearchChange: (value: string) => void;
  queryResult: UseInfiniteQueryResult<
    AxiosResponse<PaginatedResponse<T>, any>,
    unknown
  >;
  headerContent?: React.ReactNode;
};

const PeopleSelection = ({
  fieldName = 'users',
  selectionMode = 'multiple',
  search,
  onSearchChange,
  queryResult,
  headerContent,
}: Props<User>) => {
  const form = useFormContext();
  const isSingleMode = selectionMode === 'single';
  const formUsers = useWatch({ control: form.control, name: fieldName });

  const {
    data: users,
    isLoading,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = queryResult;
  const usersList = users?.pages.flatMap(page => page.data.items) || [];

  const handleSelectUser = useCallback(
    (user: User) => {
      if (isSingleMode) {
        form.setValue(fieldName, formUsers?.id === user.id ? null : user, {
          shouldValidate: true,
        });
        return;
      }
      form.setValue(
        fieldName,
        formUsers?.some((u: User) => u.id === user.id)
          ? formUsers.filter((u: User) => u.id !== user.id)
          : [...(formUsers || []), user],
      );
    },
    [formUsers, isSingleMode, fieldName],
  );

  const isUserSelected = useCallback(
    (user: User): boolean => {
      if (isSingleMode) return formUsers?.id === user.id;
      return formUsers?.some((u: User) => u.id === user.id) ?? false;
    },
    [formUsers, isSingleMode],
  );

  return (
    <Stack sx={{ gap: 3 }}>
      {headerContent}
      <HuSearch
        value={search}
        onChange={onSearchChange}
      />
      <InfiniteList
        isSuccess={!!users}
        isLoading={isLoading}
        isEmpty={!!users?.pages && !users.pages.length}
        fetchNextPage={fetchNextPage}
        hasNextPage={!!hasNextPage}
        isFetchingNextPage={isFetchingNextPage}
      >
        <Stack>
          {usersList.map(user => (
            <PeopleItemList
              key={user.id}
              user={user}
              isSelected={isUserSelected(user)}
              handleSelectUser={handleSelectUser}
              selectionMode={selectionMode}
            />
          ))}
        </Stack>
      </InfiniteList>
    </Stack>
  );
};

export default PeopleSelection;
