import { useEffect, useState } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { type UseQueryResult } from 'react-query';

import { useDebounce } from '@material-hu/hooks/useDebounce';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuAvatar from '@material-hu/components/design-system/Avatar';
import HuFormAutocomplete from '@material-hu/components/design-system/Inputs/Autocomplete/form';
import { type AutocompleteProps as HuAutocompleteProps } from '@material-hu/components/design-system/Inputs/Autocomplete/types';

import { type User } from 'src/types/user';
import { getFullName, getInitials } from 'src/utils/userUtils';

type UserOption = {
  label: string;
  value: number;
  id: number;
  profilePicture?: string;
};

export type BaseUser = {
  id: number | string;
  firstName: string;
  lastName: string;
  email?: string | null;
  profilePicture?: string | null;
};

export type FormUserAutocompleteProps = {
  name: string;
  needSubordinates?: boolean;
  needAcknowledged?: boolean;
  usersQuery: (search: string) => UseQueryResult<BaseUser[]>;
  getOptionDisabled?: (option: User) => boolean;
  multiple?: boolean;
} & Omit<
  HuAutocompleteProps<UserOption, true>,
  'options' | 'onChange' | 'value' | 'multiple'
>;

export const FormUserAutocomplete = (props: FormUserAutocompleteProps) => {
  const {
    name,
    usersQuery,
    getOptionDisabled,
    multiple = true,
    ...autocompleteProps
  } = props;
  const [search, setSearch] = useState('');
  const selectedUsers = useWatch({ name });
  const { setValue } = useFormContext();
  const debouncedSearch = useDebounce(search, 300);

  const { data, isLoading } = usersQuery(debouncedSearch);

  const mappedOptions = (data || []).map(user => ({
    label: getFullName(user),
    value: user.id,
    id: user.id,
    profilePicture: user.profilePicture,
  }));
  /* 
    This is to prevent a warning stating that the selected value is not found on the options
    (when the selected user was searched and not present on the first 20 results)
    So the selected options are added to the options array and duplicates are removed based on id
  */
  const userOptions: UserOption[] = [...mappedOptions, ...selectedUsers].reduce(
    (acc: UserOption[], currentUser: UserOption) =>
      acc.find(user => user.id === currentUser.id)
        ? acc
        : [...acc, currentUser],
    [],
  );

  useEffect(() => {
    if (!multiple && selectedUsers.length > 1) {
      setValue(name, [selectedUsers[selectedUsers.length - 1]], {
        shouldDirty: true,
      });
    }
  }, [multiple, selectedUsers, setValue, name]);

  return (
    <HuFormAutocomplete
      name={name}
      options={userOptions}
      autocompleteProps={{
        onInputChange: (_, value) => setSearch(value),
        loading: isLoading,
        getOptionDisabled,
        isServerFiltered: true,
        multiple: true,
        slotProps: {
          paper: {
            sx: {
              '& .MuiAutocomplete-option': {
                px: 2,
                py: 1,
              },
            },
          },
        },
        renderOption: (optionProps, option) => {
          const { key, ...restOfProps } = optionProps; // If key prop is passed via spread it will throw an error on console
          return (
            <li
              key={key}
              {...restOfProps}
            >
              <Stack
                sx={{ flexDirection: 'row', alignItems: 'center', gap: 2 }}
              >
                <HuAvatar
                  src={
                    userOptions.find(user => user.id === option.value)
                      ?.profilePicture
                  }
                  alt=""
                  text={getInitials(option.label)}
                />
                <Typography>{option.label}</Typography>
              </Stack>
            </li>
          );
        },
        ...autocompleteProps,
        defaultValue: undefined,
      }}
    />
  );
};
