"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExportInternalApi = void 0;
const tslib_1 = require("tslib");
const ApiBase_1 = require("../Implementation/ApiBase");
const ag_grid_enterprise_1 = require("ag-grid-enterprise");
const Uuid_1 = require("../../AdaptableState/Uuid");
const GeneralConstants_1 = require("../../Utilities/Constants/GeneralConstants");
const StringExtensions_1 = tslib_1.__importDefault(require("../../Utilities/Extensions/StringExtensions"));
const FormatHelper_1 = require("../../Utilities/Helpers/FormatHelper");
const Helper_1 = tslib_1.__importDefault(require("../../Utilities/Helpers/Helper"));
const PopupRedux = tslib_1.__importStar(require("../../Redux/ActionsReducers/PopupRedux"));
const InternalRedux_1 = require("../../Redux/ActionsReducers/InternalRedux");
class ExportInternalApi extends ApiBase_1.ApiBase {
    /**
     * Value Items for Report Name Selection
     */
    getAllAvailableReportNames() {
        return this.getExportApi()
            .getAllReports()
            .map((report) => report.Name);
    }
    isDataChangeInReport(cellDataChangedInfo, report) {
        // for All Data Report any data change is true so get out asap
        if (report.Name == 'All Data') {
            return true;
        }
        // Start with the DataChanged Column and go through all possibilities
        switch (report.ReportColumnScope) {
            case 'AllColumns':
                // has to be relevant so continue to rows
                break;
            case 'ScopeColumns':
                // use the Scope object which will tell us if the Column is relevant
                if (!this.getAdaptableApi().columnScopeApi.isColumnInScopeColumns(cellDataChangedInfo.column, report.Scope)) {
                    return false;
                }
                break;
            case 'SelectedColumns':
                let selectedCellInfo = this.getAdaptableApi().gridApi.getSelectedCellInfo();
                if (selectedCellInfo) {
                    if (selectedCellInfo.columns.find((c) => c.columnId == cellDataChangedInfo.column.columnId) == null) {
                        return false;
                    }
                }
                break;
            case 'VisibleColumns':
                //  hope that visible column property is updated whenever the layout changes... (need to check!)
                if (!cellDataChangedInfo.column.visible) {
                    return false;
                }
                break;
        }
        // now do rows
        switch (report.ReportRowScope) {
            case 'AllRows':
                return true;
            case 'ExpressionRows':
                return true; // TODO this is the only difficult one - do we check AdapTableQL?  if we can then that is good as we can then do a delta after all...
            case 'SelectedRows':
                // CellSelection
                let selectedCellInfo = this.getAdaptableApi().gridApi.getSelectedCellInfo();
                if (selectedCellInfo && selectedCellInfo.gridCells) {
                    if (selectedCellInfo.gridCells.find((gc) => gc.primaryKeyValue == cellDataChangedInfo.primaryKeyValue)) {
                        return true;
                    }
                }
                // Row Selection
                let selectedRowInfo = this.getAdaptableApi().gridApi.getSelectedRowInfo();
                if (selectedRowInfo && selectedRowInfo.gridRows) {
                    if (selectedRowInfo.gridRows.find((gr) => gr.primaryKeyValue == cellDataChangedInfo.primaryKeyValue)) {
                        return true;
                    }
                }
                return false;
            case 'VisibleRows':
                return this.getGridApi().isVisibleRowNode(cellDataChangedInfo.rowNode);
        }
    }
    setExportInProgress(reportName, reportFormat, exportDestination) {
        this.dispatchAction((0, InternalRedux_1.SystemExportBegin)(reportName, reportFormat, exportDestination));
    }
    setExportComplete() {
        this.dispatchAction((0, InternalRedux_1.SystemExportEnd)());
    }
    isVisualDataExportInProgress() {
        return this.getAdaptableState().Internal.Export.inProgress?.reportFormat === 'VisualExcel';
    }
    isExcelExportInProgress() {
        return this.getAdaptableState().Internal.Export.inProgress?.reportFormat === 'Excel';
    }
    createSystemReport(systemReportName) {
        switch (systemReportName) {
            case GeneralConstants_1.ALL_DATA_REPORT:
                return {
                    Uuid: (0, Uuid_1.createUuid)(),
                    Name: GeneralConstants_1.ALL_DATA_REPORT,
                    ReportColumnScope: 'AllColumns',
                    ReportRowScope: 'AllRows',
                    Query: undefined,
                    IsReadOnly: true,
                };
            case GeneralConstants_1.CURRENT_LAYOUT_REPORT:
                return {
                    Uuid: (0, Uuid_1.createUuid)(),
                    Name: GeneralConstants_1.CURRENT_LAYOUT_REPORT,
                    ReportColumnScope: 'VisibleColumns',
                    ReportRowScope: 'VisibleRows',
                    Query: undefined,
                    IsReadOnly: true,
                };
            case GeneralConstants_1.SELECTED_DATA_REPORT:
                return {
                    Uuid: (0, Uuid_1.createUuid)(),
                    Name: GeneralConstants_1.SELECTED_DATA_REPORT,
                    ReportColumnScope: 'SelectedColumns',
                    ReportRowScope: 'SelectedRows',
                    Query: undefined,
                    IsReadOnly: true,
                };
        }
    }
    isSystemReport(reportName) {
        return GeneralConstants_1.SYSTEM_REPORT_NAMES.includes(reportName);
    }
    isSystemDestination(destination) {
        return GeneralConstants_1.SYSTEM_EXPORT_DESTINATIONS.includes(destination);
    }
    isSystemReportActive(reportName) {
        if (reportName == GeneralConstants_1.SELECTED_DATA_REPORT) {
            return (this.getAdaptableApi().gridApi.isGridRangeSelectable() ||
                this.getAdaptableApi().gridApi.isGridRowSelectable());
        }
        return true;
    }
    getReportColumnScopeShortDescription(report) {
        switch (report.ReportColumnScope) {
            case 'AllColumns':
                return ['[All Columns]'];
            case 'VisibleColumns':
                return ['[Visible Columns]'];
            case 'SelectedColumns':
                return ['[Selected Columns]'];
            case 'ScopeColumns':
                if ('ColumnIds' in report?.Scope) {
                    return report.Scope.ColumnIds.map?.((columnId) => this.getAdaptableApi().columnApi.getFriendlyNameForColumnId(columnId) ?? columnId);
                }
                return ['[Bespoke Columns]'];
        }
    }
    getReportColumnScopeLongDescription(report) {
        switch (report.ReportColumnScope) {
            case 'AllColumns':
                return '[All Columns]';
            case 'VisibleColumns':
                return '[Visible Columns]';
            case 'SelectedColumns':
                return '[Selected Columns]';
            case 'ScopeColumns':
                return this.getAdaptableApi().columnScopeApi.getScopeDescription(report.Scope);
        }
    }
    getReportExpressionDescription(report, cols) {
        if (this.isSystemReport(report.Name)) {
            return `[${report.Name}]`;
        }
        else {
            switch (report.ReportRowScope) {
                case 'AllRows':
                    return '[All Rows]';
                case 'VisibleRows':
                    return '[Visible Rows]';
                case 'SelectedRows':
                    return '[Selected Rows]';
                case 'ExpressionRows':
                    return this.getAdaptableInternalApi().getAdaptableQueryExpressionText(report.Query);
            }
        }
    }
    convertReportDataToArray(reportData) {
        return [
            reportData.columns.map((column) => column.friendlyName),
            ...reportData.rows.map((row) => reportData.columns.map((column) => row[column.field ?? column.columnId])),
        ];
    }
    publishLiveLiveDataChangedEvent(reportDestination, liveDataTrigger, liveReport) {
        const liveDataChangedInfo = {
            ...this.getAdaptableInternalApi().buildBaseContext(),
            reportDestination: reportDestination,
            liveDataTrigger: liveDataTrigger,
            liveReport: liveReport,
        };
        this.getAdaptableApi().eventApi.emit('LiveDataChanged', liveDataChangedInfo);
    }
    getReportFileName(reportName, reportFormat, destination) {
        let fileName = StringExtensions_1.default.ReplaceEmptySpacesWithUnderscore(`${reportName}-${reportFormat}`);
        const reportFilename = this.getAdaptableApi().optionsApi.getExportOptions().reportFilename;
        if (reportFilename) {
            const reportFileNameContext = {
                fileName,
                ...this.buildBaseExportContext(reportName, reportFormat, destination),
            };
            fileName = reportFilename(reportFileNameContext);
        }
        else {
            if (this.getAdaptableApi().optionsApi.getExportOptions().appendFileTimestamp) {
                fileName = `${fileName}_${(0, FormatHelper_1.DateFormatter)(new Date(), {
                    Pattern: 'yyyyMMdd_HHmmss',
                })}`;
            }
        }
        return fileName;
    }
    sendReportToDestination(reportResult, report, format, destination) {
        if (!reportResult?.data) {
            this.logWarn(`No report result to send to destination for report '${report.Name}, format '${format}' and destination '${destination}'`);
            return;
        }
        if (!this.getExportApi().isExportDestinationSystem(destination)) {
            this.sendReportToCustomDestination(reportResult, report, format, destination);
        }
        if (destination === 'Download') {
            if (reportResult.type === 'excel') {
                Helper_1.default.createDownloadedFile(reportResult.data, this.getReportFileName(report.Name, format, destination), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            }
            if (reportResult.type === 'csv') {
                Helper_1.default.createDownloadedFile(reportResult.data, this.getReportFileName(report.Name, format, destination), 'text/csv;encoding:utf-8');
            }
            if (reportResult.type === 'json') {
                Helper_1.default.createDownloadedFile(JSON.stringify(reportResult.data), this.getReportFileName(report.Name, format, destination), 'application/json');
            }
        }
        if (destination === 'Clipboard') {
            if (reportResult.type !== 'csv' && reportResult.type !== 'json') {
                this.logWarn(`Cannot copy to clipboard as report result is not a string (report '${report.Name}', format '${format}', destination '${destination}')`);
                return;
            }
            Helper_1.default.copyToClipboard(reportResult.type === 'json' ? JSON.stringify(reportResult.data) : reportResult.data);
        }
    }
    sendReportToCustomDestination(reportResult, report, format, destination) {
        const customDestination = this.getExportApi()
            .getAvailableCustomDestinations()
            .find((cd) => cd.name == destination);
        if (customDestination?.form) {
            this.getAdaptableInternalApi().dispatchReduxAction(PopupRedux.PopupShowForm({
                Id: 'export-destination-form',
                Form: customDestination?.form,
                prepareContext: (context) => {
                    // we want to give the current popup time to close
                    // and we reopen with a delay in case this button action causes another popup
                    return new Promise((resolve) => {
                        setTimeout(() => {
                            const preparedContext = {
                                ...context,
                                report,
                                customDestination,
                                reportData: reportResult,
                            };
                            resolve(preparedContext);
                        }, 20);
                    });
                },
            }));
        }
        else if (customDestination) {
            const reportContext = {
                report: report,
                reportData: reportResult,
                ...this.buildBaseExportContext(report.Name, format, destination),
            };
            customDestination.onExport(reportContext);
        }
    }
    buildBaseExportContext(reportName, reportFormat, exportDestination) {
        const report = this.getExportApi().getReportByName(reportName);
        return {
            ...this.getAdaptableInternalApi().buildBaseContext(),
            report,
            reportName,
            reportFormat,
            exportDestination,
        };
    }
    createCellCsv(cellContent) {
        return {
            data: {
                value: cellContent != undefined ? String(cellContent) : null,
            },
        };
    }
    createCellExcel(cellContent, cellType) {
        return {
            data: {
                value: cellContent != undefined ? String(cellContent) : null,
                type: cellType,
            },
        };
    }
    createCellHeader(cellContent) {
        return {
            data: {
                value: cellContent != undefined ? String(cellContent) : null,
                type: 'String',
            },
        };
    }
    buildProcessExportContext(report, format, destination) {
        const { exportContext } = this._adaptable.agGridExportAdapter.buildExportProcessData({
            report,
            format,
            destination,
            showProgressIndicator: false,
        });
        return {
            ...this.buildBaseExportContext(report.Name, format, destination),
            convertToExcel: this.buildExcelConverter(report.Name, format, destination),
            convertToCsv: this.buildCsvConverter(report.Name, format, destination),
            getReportColumns: () => exportContext.exportedColumnIds
                .map((colId) => this.getAdaptableApi().columnApi.getColumnWithColumnId(colId, false))
                .filter(Boolean),
        };
    }
    exportAllDataInPivotMode(exportProcessData) {
        const { exportContext, exportParams } = exportProcessData;
        const exportedColumns = this.getColumnApi()
            .getExportableColumns()
            .filter((column) => !column.isGeneratedPivotResultColumn && !column.isGeneratedRowGroupColumn);
        const exportedRowData = this.getGridApi().getGridData();
        const reportData = {
            columns: exportedColumns,
            rows: exportedRowData,
        };
        const exportFormat = exportContext.format;
        if (exportFormat === 'JSON') {
            return {
                data: reportData,
                type: 'json',
            };
        }
        if (exportFormat === 'CSV') {
            const csvExportConverter = this.buildCsvConverter(exportContext.report.Name, exportFormat, exportContext.destination);
            const csvData = csvExportConverter(reportData);
            return {
                data: csvData,
                type: 'csv',
            };
        }
        // theoretically 'VisualExcel' is not a valid export format for this function and should be suppressed from UI
        // but just in case, we handle it here and return a "raw", unstyled Excel file
        if (exportFormat === 'Excel' || exportFormat === 'VisualExcel') {
            const excelExportConverter = this.buildExcelConverter(exportContext.report.Name, exportFormat, exportContext.destination);
            const excelData = excelExportConverter(reportData);
            return {
                data: excelData,
                type: 'excel',
            };
        }
    }
    buildExcelConverter(reportName, reportFormat, exportDestination) {
        return (reportData) => {
            return this.executeGridExport(reportData, reportName, reportFormat, exportDestination, (gridApi, exportParams) => gridApi.getDataAsExcel({ ...exportParams }));
        };
    }
    buildCsvConverter(reportName, reportFormat, exportDestination) {
        return (reportData) => {
            const csvParams = this.buildCsvExportParams(reportName, reportFormat, exportDestination);
            return this.executeGridExport(reportData, reportName, reportFormat, exportDestination, (gridApi, exportParams) => gridApi.getDataAsCsv({ ...exportParams, ...csvParams }));
        };
    }
    executeGridExport(reportData, reportName, reportFormat, exportDestination, exportFn) {
        const htmlDivElement = document.createElement('div');
        let ephemeralGridApi = null;
        try {
            const columnDefs = reportData.columns.map((col) => ({
                colId: col.columnId,
                field: col.field ?? col.columnId,
                headerName: col.friendlyName ?? col.columnId,
                cellDataType: col.dataType ?? 'text',
            }));
            const gridOptions = {
                columnDefs,
                rowData: reportData.rows,
                theme: this.getAgGridApi().getGridOption('theme'),
                dataTypeDefinitions: this.getAgGridApi().getGridOption('dataTypeDefinitions'),
                columnTypes: this.getAgGridApi().getGridOption('columnTypes'),
            };
            const gridParams = {
                modules: this.getAdaptableApi()
                    .internalApi.getAgGridModulesAdapter()
                    .getAgGridRegisteredModules(),
            };
            htmlDivElement.style.display = 'none';
            document.body.appendChild(htmlDivElement);
            ephemeralGridApi = (0, ag_grid_enterprise_1.createGrid)(htmlDivElement, gridOptions, gridParams);
            const exportParams = {
                fileName: this.getReportFileName(reportName, reportFormat, exportDestination),
                allColumns: true,
                exportedRows: 'all',
            };
            return exportFn(ephemeralGridApi, exportParams);
        }
        catch (error) {
            this.logWarn('Failed to export data:', error);
            return null;
        }
        finally {
            if (ephemeralGridApi) {
                ephemeralGridApi.destroy();
            }
            if (htmlDivElement?.parentNode) {
                document.body.removeChild(htmlDivElement);
            }
        }
    }
    buildCsvExportParams(reportName, reportFormat, exportDestination) {
        const exportOptions = this.getAdaptableApi().optionsApi.getExportOptions();
        const csvSeparator = typeof exportOptions.csvSeparator === 'function'
            ? exportOptions.csvSeparator(this.buildBaseExportContext(reportName, reportFormat, exportDestination))
            : exportOptions.csvSeparator;
        return {
            columnSeparator: csvSeparator,
        };
    }
}
exports.ExportInternalApi = ExportInternalApi;
