import { RequestStatus } from '../../../../types/UserReports.js';
import { ReportStoreService } from '../../../../services/reportStoreService.js';
import { getDpdPathSuffix } from '../../../../utils/urlHelper.js';
import logger from '../../../../utils/logger.js';

class RequestedReportService extends ReportStoreService {
    constructor(userDataStore) {
        super(userDataStore);
    }
    async addReport(userId, reportStateData) {
        const userConfig = await this.getState(userId);
        userConfig.requestedReports.unshift(reportStateData);
        await this.saveState(userId, userConfig);
    }
    async removeReport(executionId, userId) {
        const userConfig = await this.getState(userId);
        const index = this.findIndexByExecutionId(executionId, userConfig.requestedReports);
        userConfig.requestedReports.splice(index, 1);
        await this.saveState(userId, userConfig);
    }
    async getReportByExecutionId(id, userId) {
        const userConfig = await this.getState(userId);
        return userConfig.requestedReports.find((report) => report.executionId === id);
    }
    async getReportByTableId(id, userId) {
        const userConfig = await this.getState(userId);
        return userConfig.requestedReports.find((report) => report.tableId === id);
    }
    async getAllReports(userId) {
        const userConfig = await this.getState(userId);
        return userConfig.requestedReports;
    }
    async getAllReportsById(id, userId) {
        const userConfig = await this.getState(userId);
        return userConfig.requestedReports.filter((requested) => {
            return (requested.id && requested.id === id) || (requested.variantId && requested.variantId === id);
        });
    }
    async updateLastViewed(id, userId) {
        const userConfig = await this.getState(userId);
        const index = this.findIndexByExecutionId(id, userConfig.requestedReports);
        if (index === -1) {
            return;
        }
        const report = userConfig.requestedReports[index];
        report.timestamp.lastViewed = new Date();
        userConfig.requestedReports[index] = report;
        await this.saveState(userId, userConfig);
    }
    async updateStatus(id, userId, status, errorMessage) {
        const userConfig = await this.getState(userId);
        const index = this.findIndexByExecutionId(id, userConfig.requestedReports);
        if (index === -1) {
            return;
        }
        let report = userConfig.requestedReports[index];
        if (report)
            report = this.updateDataByStatus(report, status, errorMessage);
        userConfig.requestedReports[index] = report;
        await this.saveState(userId, userConfig);
    }
    async setToExpired(id, userId) {
        const userConfig = await this.getState(userId);
        const index = this.findIndexByExecutionId(id, userConfig.requestedReports);
        if (index === -1) {
            return;
        }
        await this.saveExpiredState(userConfig, index, userId);
    }
    async setToExpiredByTableId(id, userId) {
        const userConfig = await this.getState(userId);
        const index = this.findIndexByTableId(id, userConfig.recentlyViewedReports);
        if (index !== -1) {
            await this.saveExpiredState(userConfig, index, userId);
        }
        else {
            logger.info(`Unable to expire requested report - ${id} not found in state`);
        }
    }
    async saveExpiredState(userConfig, index, userId) {
        const report = userConfig.requestedReports[index];
        if (!report || report.status === RequestStatus.EXPIRED) {
            return;
        }
        const updated = {
            ...report,
            status: RequestStatus.EXPIRED,
            timestamp: {
                ...report.timestamp,
                expired: new Date(),
            },
        };
        userConfig.requestedReports[index] = updated;
        await this.saveState(userId, userConfig);
    }
    /**
     * Removes old stale data from requested reports
     * - When a report is viewed it is given a lastViewed ts.
     * - If the requested data has a lastViewed ts and
     * - has no corresponding viewed entry
     * - then that requested data is stale and can be removed
     *
     * @param {string} userId
     * @param {StoredReportData[]} viewedReports
     * @memberof RequestedReportService
     */
    async cleanList(userId, viewedReports) {
        const userConfig = await this.getState(userId);
        const allRequested = userConfig.requestedReports;
        const viewedRequestedReports = allRequested.filter((requestedReport) => {
            return requestedReport.timestamp.lastViewed !== undefined;
        });
        let count = 0;
        await Promise.all(viewedRequestedReports.map(async (viewedRequestReport) => {
            const { executionId } = viewedRequestReport;
            const viewedReport = viewedReports.find((report) => {
                const { executionId: viewedExecutionId } = report;
                return viewedExecutionId && viewedExecutionId === executionId;
            });
            if (!viewedReport && executionId) {
                await this.removeReport(executionId, userId);
                count += 1;
            }
        }));
        if (count > 0)
            logger.info(`RequestedReports: Removed ${count} stale reports from list`);
    }
    setReportUrl(report) {
        const { tableId, url, dpdPathFromQuery, dataProductDefinitionsPath, type } = report;
        let pathname;
        let fullUrl;
        if (url && url.polling?.pathname) {
            let reportUrlArr = Array.from(new Array(2));
            reportUrlArr = url.polling.pathname.replace('/request-report', '/view-report/async').split('/');
            reportUrlArr[reportUrlArr.length - 2] = tableId;
            reportUrlArr[reportUrlArr.length - 1] = type;
            const reportUrl = reportUrlArr.join('/');
            const search = url.report?.search ? url.report.search : '';
            const dpdPath = dataProductDefinitionsPath && dpdPathFromQuery ? `${getDpdPathSuffix(dataProductDefinitionsPath)}` : '';
            const searchPath = search || dpdPath;
            pathname = `${reportUrl}${searchPath}`;
            fullUrl = `${url.origin}${pathname}`;
        }
        return {
            pathname,
            fullUrl,
        };
    }
    updateDataByStatus(report, status, errorMessage) {
        const ts = new Date();
        if (status)
            report.status = status;
        switch (status) {
            case RequestStatus.FAILED:
                report.timestamp.failed = ts;
                if (errorMessage)
                    report.errorMessage = errorMessage;
                break;
            case RequestStatus.EXPIRED:
                report.timestamp.expired = ts;
                break;
            case RequestStatus.ABORTED:
                report.timestamp.aborted = ts;
                break;
            case RequestStatus.FINISHED: {
                report.timestamp.completed = ts;
                if (report.url) {
                    report.url.report = {
                        ...report.url.report,
                        ...this.setReportUrl(report),
                    };
                }
                break;
            }
            case RequestStatus.SUBMITTED:
                report.timestamp.requested = ts;
                break;
            case RequestStatus.STARTED:
            case RequestStatus.PICKED:
                break;
            default:
                report.timestamp.lastViewed = ts;
                break;
        }
        return report;
    }
    /**
     * Remove duplicate report from state
     *
     * @param {RequestedReport[]} reports
     * @return {*}  {RequestedReport[]}
     * @memberof RequestedReportService
     */
    removeDuplicateRequestedReports = async (userId) => {
        const reports = await this.getAllReports(userId);
        if (reports.length < 2) {
            return [];
        }
        // Get the newest report
        const latest = reports[0];
        const latestFilters = latest.url?.request?.search?.trim() ?? '';
        const duplicates = reports.slice(1).filter((report) => {
            if (!report.executionId) {
                return false;
            }
            const sameReport = report.reportId === latest.reportId && report.id === latest.id;
            if (!sameReport) {
                return false;
            }
            const reportFilters = report.url?.request?.search?.trim() ?? '';
            return report.executionId === latest.executionId || reportFilters === latestFilters;
        });
        await Promise.all(duplicates.map(({ executionId }) => {
            return this.removeReport(executionId || '', userId);
        }));
        return duplicates.map(({ executionId }) => executionId || '');
    };
}

export { RequestedReportService, RequestedReportService as default };
//# sourceMappingURL=service.js.map
