import dayjs from 'dayjs';
import customParse from '../../_virtual/customParseFormat.js';
import { RequestStatus, ReportType } from '../types/UserReports.js';
import logger from './logger.js';
import localsHelper from './localsHelper.js';
import { ErrorHandler } from './ErrorHandler/ErrorHandler.js';

dayjs.extend(customParse);
const BAD_REQUEST_STATUSES = [RequestStatus.ABORTED, RequestStatus.FAILED, RequestStatus.EXPIRED];
const IN_PROGRESS_REQUEST_STATUSES = [
    RequestStatus.SUBMITTED,
    RequestStatus.STARTED,
    RequestStatus.PICKED,
];
function findWorstStatusResponse(statusRequests) {
    return Promise.all(statusRequests).then((statusResponses) => {
        const badStatus = statusResponses.find((response) => typeof response.status === 'number' || BAD_REQUEST_STATUSES.includes(response.status));
        if (badStatus) {
            return badStatus;
        }
        const inProgressStatus = statusResponses.find((response) => IN_PROGRESS_REQUEST_STATUSES.includes(response.status));
        if (inProgressStatus) {
            return inProgressStatus;
        }
        return statusResponses[0];
    });
}
const getStatusByReportType = async (services, req, res, token, userId) => {
    const { definitionsPath } = localsHelper.getValues(res);
    const { type, reportId, executionId, id, tableId } = req.body;
    const requestedReport = await services.requestedReportService.getReportByExecutionId(executionId, userId);
    const reports = requestedReport?.childExecutionData ?? [];
    let statusRequests = [];
    if (type === ReportType.REPORT) {
        reports.push({ executionId, tableId, variantId: id });
        statusRequests = reports.map((executionData) => {
            return services.reportingService.getAsyncReportStatus(token, reportId, executionData.variantId, executionData.executionId || '', definitionsPath, executionData.tableId || '');
        });
    }
    if (type === ReportType.DASHBOARD) {
        statusRequests.push(services.dashboardService.getAsyncStatus(token, reportId, id, executionId, tableId, definitionsPath));
    }
    const statusResponse = await findWorstStatusResponse(statusRequests);
    return {
        status: statusResponse.status,
        statusResponse,
    };
};
const getStatus = async ({ req, res, services, }) => {
    const { token, dprUser } = localsHelper.getValues(res);
    const { status: currentStatus, requestedAt } = req.body;
    const timeoutExemptStatuses = [RequestStatus.READY, RequestStatus.EXPIRED, RequestStatus.FAILED];
    let status;
    let errorMessage;
    let statusResponse;
    try {
        const statusResponseData = await getStatusByReportType(services, req, res, token, dprUser.id);
        statusResponse = statusResponseData.statusResponse;
        status = statusResponseData.status;
        if (shouldTimeoutRequest({ requestedAt, compareTime: new Date(), durationMins: 15 }) &&
            !timeoutExemptStatuses.includes(status)) {
            throw new Error('Request taking too long. Request Halted');
        }
        if (status === RequestStatus.FAILED) {
            logger.error(`Error: ${JSON.stringify(statusResponse.error)}`);
            errorMessage = new ErrorHandler(statusResponse.error).formatError();
        }
    }
    catch (error) {
        errorMessage = new ErrorHandler(error).formatError();
        status = currentStatus === RequestStatus.FINISHED ? RequestStatus.EXPIRED : RequestStatus.FAILED;
    }
    if (typeof status === 'number') {
        status = RequestStatus.FAILED;
    }
    return {
        status,
        ...(errorMessage && { errorMessage }),
    };
};
/**
 * Gets the expired status of a viewed report
 * - if reports status was READY/FINISHED
 * - And the new Status is an error status
 * - it means the report has expired
 *
 * @param {AsyncReportUtilsParams} { req, res, services }
 * @return {*}
 */
const getExpiredStatus = async ({ req, res, services }) => {
    const { token, dprUser } = localsHelper.getValues(res);
    const { executionId, status: currentStatus } = req.body;
    let errorMessage;
    let status;
    try {
        const statusData = await getStatusByReportType(services, req, res, token, dprUser.id);
        status = statusData.status;
    }
    catch (error) {
        errorMessage = new ErrorHandler(error).formatError();
        status =
            currentStatus === RequestStatus.READY || currentStatus === RequestStatus.FINISHED
                ? RequestStatus.EXPIRED
                : RequestStatus.FAILED;
    }
    const result = {
        status,
        ...(errorMessage && { errorMessage }),
    };
    return {
        isExpired: result.status === RequestStatus.EXPIRED,
        executionId,
    };
};
const shouldTimeoutRequest = ({ requestedAt, compareTime, durationMins, }) => {
    const compareDate = dayjs(compareTime);
    const requestDate = dayjs(requestedAt);
    const result = compareDate.diff(requestDate, 'minutes');
    return result >= durationMins;
};

export { getExpiredStatus, getStatus, shouldTimeoutRequest };
//# sourceMappingURL=requestStatusHelper.js.map
