import { useMemo } from 'react';
import { useQuery } from 'react-query';

import { getPublicUsers } from 'src/services/usersService';
import { User } from 'src/types/user';

import { usersKeys } from '../../Users/queries';

type Props = {
  users: (User | string)[];
  onSuccess?: (users: User[]) => void;
};

const useUserHydration = ({ users, onSuccess }: Props) => {
  // Separate already hydrated users from IDs that need fetching
  const { hydratedUsers: existingUsers, idsToFetch } = useMemo(() => {
    const hydratedUsers: User[] = [];
    const userIdsToFetch: string[] = [];

    users.forEach(user => {
      if (typeof user === 'string') {
        userIdsToFetch.push(user);
      } else {
        hydratedUsers.push(user);
      }
    });

    return { hydratedUsers, idsToFetch: userIdsToFetch };
  }, [users]);

  const { data: fetchedUsers, isLoading } = useQuery(
    usersKeys.usersWithParams({
      ids: idsToFetch,
      page: 0,
      limit: idsToFetch.length,
    }),
    () =>
      getPublicUsers({
        ids: idsToFetch.map(id => Number(id)),
        page: 0,
        limit: idsToFetch.length,
      }),
    {
      enabled: idsToFetch.length > 0,
      select: data => data.data.items,
      onSuccess: fetchedUsersData => {
        const allUsers = [...existingUsers, ...fetchedUsersData];
        onSuccess?.(allUsers);
      },
    },
  );

  // Combine existing hydrated users with newly fetched users
  const allHydratedUsers = useMemo(() => {
    const combined = [...existingUsers];
    if (fetchedUsers) {
      combined.push(...fetchedUsers);
    }

    // Maintain the original order based on the input array
    return users
      .map(user => {
        if (typeof user === 'string') {
          return combined.find(u => u.id === Number(user));
        }
        return user;
      })
      .filter(Boolean) as User[];
  }, [existingUsers, fetchedUsers, users]);

  return {
    hydratedUsers: allHydratedUsers,
    isLoading,
  };
};

export default useUserHydration;
