import { BioEntityContent } from '@/types/models';
import { PerfectMultiSearchParams } from '@/types/search';
import { ThunkConfig } from '@/types/store';
import { getErrorMessage } from '@/utils/getErrorMessage';
import { PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
import { addNumbersToEntityNumberData } from '../../entityNumber/entityNumber.slice';
import { MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX } from '../bioEntity.constants';
import { getBioEntity } from './getBioEntity';
import { fetchReactionsAndGetBioEntitiesIds } from './utils/fetchReactionsAndGetBioEntitiesIds';

type GetMultiBioEntityProps = PerfectMultiSearchParams;
type GetMultiBioEntityActions = PayloadAction<BioEntityContent[] | undefined | string>[]; // if error thrown, string containing error message is returned

export const getMultiBioEntity = createAsyncThunk<
  BioEntityContent[],
  GetMultiBioEntityProps,
  ThunkConfig
>(
  'project/getMultiBioEntity',
  // eslint-disable-next-line consistent-return
  async ({ searchQueries, isPerfectMatch }, { dispatch, rejectWithValue }) => {
    try {
      const asyncGetBioEntityFunctions = searchQueries.map(searchQuery =>
        dispatch(getBioEntity({ searchQuery, isPerfectMatch, addNumbersToEntityNumber: false })),
      );

      const bioEntityContentsActions = (await Promise.all(
        asyncGetBioEntityFunctions,
      )) as GetMultiBioEntityActions;

      const bioEntityContents = bioEntityContentsActions
        .map(bioEntityContentsAction => bioEntityContentsAction?.payload || [])
        .flat()
        .filter((payload): payload is BioEntityContent => typeof payload !== 'string')
        .filter(payload => 'bioEntity' in payload || {});

      const bioEntityIds = bioEntityContents.map(b => b.bioEntity.elementId);
      dispatch(addNumbersToEntityNumberData(bioEntityIds));

      const bioEntitiesIds = await fetchReactionsAndGetBioEntitiesIds({
        bioEntityContents,
        dispatch,
      });
      getMultiBioEntity({ searchQueries: bioEntitiesIds, isPerfectMatch: true });

      return bioEntityContents;
    } catch (error) {
      const errorMessage = getErrorMessage({
        error,
        prefix: MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX,
      });

      return rejectWithValue(errorMessage);
    }
  },
);