import { useSyncExternalStore } from 'react';

import debounce from 'lodash-es/debounce';

import { type Member } from 'src/pages/dashboard/Conversations/types';
import { convertUserToMember } from 'src/pages/dashboard/Conversations/utils';
import { getUserListByIds } from 'src/services/users';

import { createStore } from './createStore';

type MembersStoreState = {
  members: Record<string, Member>;
};

const membersStore = createStore<MembersStoreState>({ members: {} });

let fetchedIds = new Set<string>();

const executeFetch = debounce(() => {
  const batch = [...fetchedIds];

  getUserListByIds(batch.map(Number))
    .then(response => {
      addMembers(response.data.items.map(convertUserToMember));
    })
    .finally(() => {
      fetchedIds = new Set([...fetchedIds].filter(id => !batch.includes(id)));
    });
}, 500);

export const addMembers = (incoming: Member | Member[]) => {
  const current = membersStore.getState().members;
  const entries = Array.isArray(incoming) ? incoming : [incoming];

  const newEntries = entries.filter(m => !current[m.id.toString()]);
  if (!newEntries.length) return;

  const patch = Object.fromEntries(newEntries.map(m => [m.id.toString(), m]));
  membersStore.setState({ members: { ...current, ...patch } });
};

export const fetchMissingMembers = (ids: string[]): string[] => {
  const current = membersStore.getState().members;
  const toFetch = [
    ...new Set(ids.filter(id => !current[id] && !fetchedIds.has(id))),
  ];
  if (!toFetch.length) return [];

  fetchedIds = new Set([...fetchedIds, ...toFetch]);
  executeFetch();
  return toFetch;
};

export const getMembers = (): Record<string, Member> =>
  membersStore.getState().members;

export const useMembersStore = () => {
  const members = useSyncExternalStore(
    membersStore.subscribe,
    () => membersStore.getState().members,
  );

  return { members };
};
