/**
 * Manager that solves the problem of repeatable async calls to keep only the result for the last call
 * New timestamp can be created with the create(args) function, which gets all the arguments
 * that needed to be passed to the given asyncFunction
 * The call() function throws an error if the result is "outdated" (there was a new call fired before we received it).
 * @param {function} asyncFunction Any function that returns a Promise instance.
 * @param {object} config The configuration object. Currently takes only the getKey function that identifies
 * similar function calls to manage.
 * @returns {{create: (function(*=))}}
 */
export const createAsyncManager = (asyncFunction, config) => {
    const calls = {};
    const { getKey } = {
        getKey: (...args) => JSON.stringify(args),
        ...config,
    };
    const create = (...args) => {
        const key = getKey(...args);
        const time = Date.now();
        calls[key] = time;
        const validate = () => calls[key] === time;
        const isOutdated = () => !validate();
        const call = async () => {
            let error = null;
            let response = null;
            try {
                response = await asyncFunction(...args);
            } catch (apiError) {
                error = apiError;
            }
            if (isOutdated()) {
                // eslint-disable-next-line no-console
                console.warn('Outdated response, skipping handlers.', args);
                throw new Error(`Outdated response for the following request: ${JSON.stringify(args)}`);
            }
            if (error) {
                throw error;
            }
            return response;
        };
        return {
            call,
            validate,
            isOutdated,
        };
    };
    return {
        create,
    };
};
