import parseUrl from 'parseurl';
import { LoadType, ReportType } from '../../../../../types/UserReports.js';
import { ReportQuery } from '../../../../../types/ReportQuery.js';
import { FiltersType } from '../../../../../components/_filters/filtersTypeEnum.js';
import DefinitionUtils, { hasInteractiveFilters, getFields } from '../../../../../utils/definitionUtils.js';
import PaginationUtils from '../../../../../components/_reports/report-page/report-template/report-pagination/utils.js';
import TotalsUtils from '../../../../../components/_reports/report-page/report-template/report-totals/utils.js';
import FiltersUtils from '../../../../../components/_filters/utils.js';
import ColumnsUtils from '../../../../../components/_reports/report-heading/report-columns/report-columns-form/utils.js';
import ReportActionsUtils from '../../../../../components/_reports/report-heading/report-actions/utils.js';
import UserReportsListUtils from '../../../../../components/user-reports/utils.js';
import localsHelper from '../../../../../utils/localsHelper.js';
import ReportTemplateUtils from '../../../../../components/_reports/report-page/report-template/utils.js';
import { setUpBookmark } from '../../../../../components/bookmark/utils.js';
import { setUpDownload } from '../../../download-report/utils.js';
import { getActiveJourneyValue } from '../../../../../utils/sessionHelper.js';

const getData = async ({ res, req, services, token, userId, }) => {
    const { definitionsPath: definitionPath } = localsHelper.getValues(res);
    const { variantId, id, tableId, reportId } = (req.params);
    const reportVariantId = variantId || id;
    // Get the request data
    const requestedReportService = services.requestedReportService;
    const requestData = await requestedReportService.getReportByTableId(tableId, userId);
    const queryData = requestData?.query?.data;
    // Get the definition
    const definition = await services.reportingService.getDefinition(token, reportId, reportVariantId, definitionPath, queryData);
    const { variant } = definition;
    const { specification } = variant;
    if (!specification) {
        throw new Error('No specification found in variant definition');
    }
    // Get the columns
    const columns = ColumnsUtils.getColumns(specification, req);
    // initialise report query
    const reportQuery = await initReportQuery(definition, columns, res, req, services, requestData);
    // Get the reportData
    const reportData = await getReportData({ services, token, req, reportQuery });
    // Get the summary data, if applicable
    const { summaries } = definition.variant;
    const summariesData = !summaries ? [] : await getSummariesData(summaries, services, token, req, res);
    // Get the child data, if applicable
    const { childVariants } = definition.variant;
    const childData = !childVariants
        ? []
        : await getChildData(childVariants, services, token, req, res, requestData);
    return {
        definition,
        requestData,
        reportData,
        summariesData,
        childData,
        reportQuery,
        columns,
    };
};
const initReportQuery = async (definition, columns, res, req, services, requestData) => {
    const { definitionsPath } = localsHelper.getValues(res);
    const fields = DefinitionUtils.getFields(definition);
    const template = DefinitionUtils.getTemplate(definition);
    const filtersData = await FiltersUtils.getFilters({
        fields,
        req,
        filtersType: FiltersType.INTERACTIVE,
        res,
        services,
    });
    // Sort
    const sortColumn = req.query?.['sortColumn'] || requestData?.sortBy?.data?.['sortColumn'];
    const sortedAsc = req.query?.['sortedAsc'] || requestData?.sortBy?.data?.['sortedAsc'];
    // Pagination
    const selectedPage = req.query?.['selectedPage'];
    const pageSize = req.query?.['pageSize'];
    // Filters
    const filtersQuery = FiltersUtils.setRequestQueryFromFilterValues(filtersData.filters);
    const queryParams = {
        ...(sortColumn && { sortColumn }),
        ...(sortedAsc && { sortedAsc }),
        ...filtersQuery,
        ...(pageSize && { pageSize }),
        ...(selectedPage && { selectedPage }),
        ...(columns && { columns: columns.value }),
    };
    return new ReportQuery({
        fields,
        template,
        queryParams,
        definitionsPath,
    });
};
const getReportData = async (args) => {
    const { services, token, req, reportQuery } = args;
    const { reportId, variantId, id, tableId } = (req.params);
    const reportVariantId = variantId || id;
    return services.reportingService.getAsyncReport(token, reportId, reportVariantId, tableId, reportQuery.toRecordWithFilterPrefix(true));
};
const getSummariesData = async (summaries, services, token, req, res) => {
    const { reportId, variantId, id, tableId } = (req.params);
    const { definitionsPath: dataProductDefinitionsPath } = localsHelper.getValues(res);
    const reportVariantId = variantId || id;
    return Promise.all(summaries.map(async (summary) => {
        const summaryReport = await services.reportingService.getAsyncSummaryReport(token, reportId, reportVariantId, tableId, summary.id, {
            dataProductDefinitionsPath,
        });
        return {
            ...summary,
            data: summaryReport,
        };
    }));
};
const getChildData = async (childVariants, services, token, req, res, requestData) => {
    const { definitionsPath: dataProductDefinitionsPath } = localsHelper.getValues(res);
    const { reportId } = req.params;
    const childExecutionData = requestData?.childExecutionData;
    if (!childExecutionData) {
        throw new Error('getChildData: No execution data found for child variants');
    }
    return Promise.all(childVariants.map(async (childVariant) => {
        const { specification } = childVariant;
        if (!specification) {
            throw new Error('getChildData: No specification found in child variant definition');
        }
        const query = new ReportQuery({
            fields: specification?.fields || [],
            template: 'parent-child',
            queryParams: req.query,
            definitionsPath: dataProductDefinitionsPath,
        }).toRecordWithFilterPrefix(true);
        const childData = childExecutionData.find((e) => e.variantId === childVariant.id);
        if (!childData || !childData.tableId) {
            throw new Error('getChildData: No matching child execution data found');
        }
        const { tableId: childTableId } = childData;
        const childReport = await services.reportingService.getAsyncReport(token, reportId, childVariant.id, childTableId, query);
        return {
            id: childVariant.id,
            data: childReport,
        };
    }));
};
/**
 * Entry point function to render the report
 *
 * @param {AsyncReportUtilsParams} { req, res, services }
 * @return {*}
 */
const renderReport = async ({ req, res, services }) => {
    const { token, dprUser } = localsHelper.getValues(res);
    // Get the report data
    const { definition, requestData, reportData, childData, summariesData, reportQuery, columns } = await getData({
        req,
        res,
        services,
        token,
        userId: dprUser.id,
    });
    // Get the data table
    const dataTable = ReportTemplateUtils.createReportTemplateData(definition, columns, reportData, childData, summariesData, reportQuery);
    // Get the template data
    const templateData = await getTemplateData(req, res, services, definition, dataTable, columns, reportQuery, requestData);
    const renderData = {
        ...templateData,
        dataTable,
    };
    if (requestData && Object.keys(requestData).length) {
        UserReportsListUtils.updateLastViewed({
            req,
            services,
            reportStateData: requestData,
            userId: dprUser.id,
            filters: templateData.filterData.filters,
        });
    }
    return { renderData };
};
const getTemplateData = async (req, res, services, definition, dataTable, columns, reportQuery, requestData) => {
    // get url data
    const url = parseUrl(req);
    if (!url) {
        throw new Error('Unable to set url data from request');
    }
    // get from definition
    const definitionData = extractDataFromDefinition(definition);
    const { fields, specification } = definitionData;
    // get from requestedData
    const requestedData = requestData ? extractDataFromRequest(requestData) : undefined;
    // Get the count
    const count = await getCount(definition, services, res, req, reportQuery);
    // Get the filters
    const filterData = await FiltersUtils.getFilters({
        fields,
        req,
        res,
        services,
        filtersType: FiltersType.INTERACTIVE,
    });
    // Set the features
    const features = await setFeatures(services, res, req, columns, definitionData, requestedData);
    // Set the extra meta data
    const meta = setMetaData(res, req);
    let pagination;
    let totals;
    if (definitionData.template === 'list') {
        pagination = PaginationUtils.getPaginationData(url, count, req);
        const { pageSize, currentPage, totalRows } = pagination;
        totals = TotalsUtils.getTotals(pageSize, currentPage, totalRows, dataTable.rowCount);
    }
    return {
        ...(showColumns(specification) && { columns }),
        filterData,
        count,
        ...meta,
        ...features,
        ...definitionData,
        ...requestedData,
        ...(pagination && { pagination }),
        ...(totals && { totals }),
    };
};
const showColumns = (specification) => {
    const { template } = specification;
    return !['row-section', 'row-section-child', 'summary', 'summary-section'].includes(template);
};
const setMetaData = (res, req) => {
    const { csrfToken } = localsHelper.getValues(res);
    const { tableId, reportId, id } = req.params;
    return {
        csrfToken,
        loadType: LoadType.ASYNC,
        type: ReportType.REPORT,
        tableId,
        reportId,
        id,
    };
};
const setFeatures = async (services, res, req, columns, definitionData, requestData) => {
    const { tableId, reportId, id } = req.params;
    const bookmarkConfig = setUpBookmark(res, req, services.bookmarkService);
    const downloadConfig = setUpDownload(res, req, definitionData, columns, LoadType.ASYNC, requestData);
    const actions = ReportActionsUtils.setActions(definitionData, downloadConfig, requestData);
    const feedbackSubmissionFormPath = getActiveJourneyValue(req, { id, reportId, tableId }, 'feedbackSubmissionFormPath');
    return {
        actions,
        downloadConfig,
        bookmarkConfig,
        feedbackFormHref: feedbackSubmissionFormPath,
    };
};
const getCount = async (definition, services, res, req, reportQuery) => {
    const { token } = localsHelper.getValues(res);
    const { tableId, reportId, id } = req.params;
    return !definition.variant.interactive || !hasInteractiveFilters(getFields(definition))
        ? services.reportingService.getAsyncCount(token, tableId)
        : services.reportingService.getAsyncInteractiveCount(token, tableId, reportId, id, reportQuery);
};
const extractDataFromDefinition = (definition) => {
    const { variant, name: reportName, description: reportDescription } = definition;
    const { classification, printable, specification, name, description } = variant;
    if (!specification) {
        throw new Error('No specification found in variant definition');
    }
    const { template, fields } = specification;
    return {
        reportName,
        name,
        description: description || reportDescription,
        classification,
        printable: Boolean(printable),
        specification,
        template,
        fields,
    };
};
const extractDataFromRequest = (requestData) => {
    const { query, url, timestamp } = requestData;
    return {
        executionId: requestData.executionId,
        requestedTimestamp: timestamp.requested ? new Date(timestamp.requested).toLocaleString() : undefined,
        querySummary: query?.summary || [],
        queryData: query?.data,
        requestUrl: url?.request,
        defaultQuery: url?.report?.default,
        dataProductDefinitionsPath: requestData.dataProductDefinitionsPath,
    };
};
var AsyncReportUtils = {
    renderReport,
    extractDataFromDefinition,
};

export { AsyncReportUtils as default, getChildData, getData, getSummariesData, renderReport };
//# sourceMappingURL=utils.js.map
