import { createExportAsyncJob, getExportAsyncJob, } from '@wix/bex-utils/@wix/ambassador-fedinfra-exportservice-v1-export-async-job/http';
import { Status as JobStatus, } from '@wix/bex-utils/@wix/ambassador-fedinfra-exportservice-v1-export-async-job/types';
import { InMemoryBackend } from '../InMemoryBackend';
import { EventEmitter } from 'events';
import { Chance } from 'chance';
import { isHttpError } from '../util/isHttpError';
export function exportServiceMocks(whenRequest) {
    const chance = new Chance();
    const events = new EventEmitter();
    const buildExportAsyncJob = (params = {}) => {
        const { createDate = new Date(), updateDate = createDate, ...rest } = params;
        return {
            id: chance.guid(),
            status: JobStatus.INITIALIZED,
            ...rest,
            data: {
                iterationsCount: 0,
                processedItemsCount: 0,
                ...rest.data,
            },
            createDate,
            updateDate,
        };
    };
    const be = new InMemoryBackend({
        createOne: () => buildExportAsyncJob(),
        itemKey: (item) => item.id,
        total: 0,
    });
    async function simulateJobIterations(initialJob) {
        let job = initialJob;
        try {
            const maxIterationsCount = 4;
            while (job.data?.iterationsCount != null &&
                job.data.iterationsCount < maxIterationsCount) {
                await new Promise((resolve) => setTimeout(resolve, 100));
                const paging = job.data.query?.paging ?? job.data.query?.cursorPaging;
                job = {
                    ...job,
                    status: JobStatus.PROCESSING,
                    data: {
                        ...job.data,
                        iterationsCount: job.data.iterationsCount + 1,
                        processedItemsCount: (job.data.processedItemsCount ?? 0) + (paging?.limit ?? 0),
                    },
                };
                await Promise.all(events.listeners('processing').map((fn) => fn(job)));
                await be.update(job);
            }
            const completedJobOverrides = events.listeners('jobCompleted').reduce((prev, current) => ({
                ...prev,
                ...current(job),
            }), {});
            await be.update({
                ...job,
                status: JobStatus.FINISHED,
                ...completedJobOverrides,
                data: {
                    ...job.data,
                    ...completedJobOverrides.data,
                },
            });
            const beforeUpdateSignedUrlOverrides = (await Promise.all(events
                .listeners('beforeUpdateSignedUrl')
                .map(async (f) => (await f(job)) ?? {}))).reduce((prev, current) => ({
                ...prev,
                ...current,
            }), {});
            await be.update({
                ...job,
                status: JobStatus.FINISHED,
                ...beforeUpdateSignedUrlOverrides,
                data: {
                    ...job.data,
                    signedUrl: '/export.csv',
                    ...beforeUpdateSignedUrlOverrides.data,
                },
            });
        }
        catch (e) {
            await be.update({
                ...job,
                status: JobStatus.FAILED,
                data: {
                    ...job.data,
                    error: {
                        applicationError: {
                            code: e.message,
                        },
                        ...e,
                    },
                },
            });
        }
    }
    return {
        mocks: [
            whenRequest(createExportAsyncJob)
                .reply(async (data) => {
                try {
                    const paging = data.query.paging ?? data.query.cursorPaging;
                    if (paging?.limit == null) {
                        throw new Error('ExportServiceMocks: paging.limit is required');
                    }
                    const job = buildExportAsyncJob({
                        data,
                    });
                    await Promise.all(events.listeners('beforeCreateJob').map((fn) => fn(job)));
                    await be.push([job]);
                    await Promise.all(events.listeners('jobCreated').map((fn) => fn(job)));
                    simulateJobIterations(job);
                    return {
                        status: 200,
                        data: {
                            job,
                        },
                    };
                }
                catch (e) {
                    console.error(e);
                    if (isHttpError(e) && e.response) {
                        return {
                            status: e.response.status,
                            data: e.response.data,
                        };
                    }
                    return {
                        status: 504,
                        data: {},
                    };
                }
            })
                .persist(),
            whenRequest(getExportAsyncJob)
                .reply(200, async (data) => {
                const job = be.get(data.jobId);
                await Promise.all(events.listeners('beforeGetJob').map((fn) => fn(job)));
                return {
                    __applicationErrorsType: {},
                    job,
                };
            })
                .persist(),
        ],
        be,
        events,
    };
}
//# sourceMappingURL=exportServiceMocks.js.map