import { useMemo, useState } from 'react';
import { useFormContext } from 'react-hook-form';

import Stack from '@material-hu/mui/Stack';

import HuAvatar from '@material-hu/components/design-system/Avatar';
import HuCheckbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import HuFormAutocomplete from '@material-hu/components/design-system/Inputs/Autocomplete/form';
import HuMenuItem from '@material-hu/components/design-system/Menu/components/MenuItem';
import HuSkeleton from '@material-hu/components/design-system/Skeleton';
import HuTitle from '@material-hu/components/design-system/Title';

import {
  transformUsersToOptions,
  useHydratedUsers,
} from 'src/pages/dashboard/Workflows/utils';
import { useInfiniteUsersPublicSearch } from 'src/services/usersQueries';
import { type User } from 'src/types/user';
import { getFullname } from 'src/utils/userUtils';

import { InfiniteList } from '../InfiniteList';

const Infinite = ({
  usersInfiniteQuery,
  options,
}: {
  usersInfiniteQuery: ReturnType<typeof useInfiniteUsersPublicSearch>;
  options: (User & { label: string; value: number })[];
}) => (
  <InfiniteList
    isSuccess={!!usersInfiniteQuery.data}
    isLoading={usersInfiniteQuery.isLoading}
    isEmpty={!options.length}
    fetchNextPage={usersInfiniteQuery.fetchNextPage}
    hasNextPage={!!usersInfiniteQuery.hasNextPage}
    isFetchingNextPage={usersInfiniteQuery.isFetchingNextPage}
    renderSkeleton={
      <Stack sx={{ flexDirection: 'row', gap: 2, alignItems: 'center', mx: 2 }}>
        <HuSkeleton
          variant="rectangular"
          height={20}
          width={25}
          sx={{
            borderRadius: 0.5,
          }}
        />
        <HuSkeleton
          variant="circular"
          width={45}
          height={35}
        />
        <HuSkeleton
          variant="text"
          height={40}
          sx={{
            borderRadius: 1,
            width: '100%',
          }}
        />
      </Stack>
    }
    sx={{
      p: 0,
    }}
  >
    <div />
  </InfiniteList>
);

type Props = {
  name: string;
  autocompleteProps?: Record<string, unknown>;
  extraSearchParams?: Record<string, unknown>;
};

const PublicSearchHugoUsersAutocomplete = ({
  name,
  autocompleteProps,
  extraSearchParams,
}: Props) => {
  const [search, setSearch] = useState('');
  const { watch, setValue, getValues } = useFormContext();
  const multiple = Boolean(autocompleteProps?.multiple);

  // biome-ignore lint/correctness/useExhaustiveDependencies: same pattern as HugoUsersAutocomplete
  const selectedIds = useMemo(() => {
    const v = getValues(name);
    if (v == null) {
      return undefined;
    }
    if (Array.isArray(v)) {
      return v
        .map((x: unknown) => (typeof x === 'number' ? x : (x as User)?.id))
        .filter((id): id is number => typeof id === 'number');
    }
    if (typeof v === 'object' && 'id' in v) {
      return [(v as User).id];
    }
    return undefined;
  }, []);

  const handleSetValue = (users: User[]) => {
    setValue(name, multiple ? users : (users[0] ?? null));
  };

  const { isFetching: isFetchingHydrated } = useHydratedUsers(
    (selectedIds ?? []) as number[],
    true,
    handleSetValue,
  );

  const usersInfiniteQuery = useInfiniteUsersPublicSearch({
    search,
    limit: 10,
    ...extraSearchParams,
  });

  const selectedValue = watch(name);
  const limitReached =
    multiple &&
    (selectedValue as unknown[])?.length ===
      (autocompleteProps?.limitTags as number | undefined);
  const hasSelectedValues = multiple
    ? !!(selectedValue as unknown[])?.length
    : selectedValue != null && selectedValue !== '';

  const options = useMemo(
    () => transformUsersToOptions(usersInfiniteQuery?.data?.pages),
    [usersInfiniteQuery?.data?.pages],
  );

  return (
    <HuFormAutocomplete
      name={name}
      options={options}
      autocompleteProps={{
        limitTags: (autocompleteProps?.limitTags as number | undefined) || 3,
        isOptionEqualToValue: (option, value) =>
          (option as User)?.id === (value as User)?.id,
        ...(isFetchingHydrated && {
          renderTags: () => (
            <HuSkeleton
              variant="rounded"
              width={140}
              height={26}
              sx={{ ml: 0.5, my: 1 }}
            />
          ),
        }),
        renderOption: (props, option, { selected, index }) => {
          const user = option as User;
          const { key, ...rest } = props;
          const isLast = index === options.length - 1;

          return (
            <>
              <HuMenuItem
                selected={selected}
                disabled={!selected && limitReached}
                key={key}
                {...rest}
                sx={{ gap: 2 }}
              >
                {multiple && <HuCheckbox checked={selected} />}
                <HuAvatar
                  src={user.profilePicture || undefined}
                  size="medium"
                  sx={{ my: 1 }}
                />
                <HuTitle
                  variant="S"
                  title={getFullname(user)}
                  description={user.employeeInternalId}
                />
              </HuMenuItem>
              {isLast && (
                <Infinite
                  usersInfiniteQuery={usersInfiniteQuery}
                  options={options}
                />
              )}
            </>
          );
        },
        onInputChange: (_, value) => setSearch(value),
        loading:
          usersInfiniteQuery.isFetchingNextPage ||
          usersInfiniteQuery.isFetching,
        isServerFiltered: true,
        ...autocompleteProps,
        placeholder: hasSelectedValues
          ? undefined
          : (autocompleteProps?.placeholder as string | undefined),
      }}
    />
  );
};

export default PublicSearchHugoUsersAutocomplete;
