'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var urlHelper = require('../urlHelper.js');
var DateMapper = require('../DateMapper/DateMapper.js');

class DataTableBuilder {
    fields;
    sortData;
    columns = [];
    reportSummaries = {};
    // Sortable headers only
    reportQuery = null;
    currentQueryParams = null;
    dateMapper = new DateMapper.DateMapper();
    constructor(fields, sortData = false) {
        this.fields = fields;
        this.sortData = sortData;
    }
    mapDate(isoDate) {
        if (!isoDate)
            return '';
        return this.dateMapper.toDateString(isoDate, 'local-datetime-short-year');
    }
    mapBoolean(value) {
        if (!value)
            return '';
        return value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase();
    }
    mapRow(rowData, extraClasses = '', overrideFields = []) {
        return this.fields
            .filter((f) => this.columns.includes(f.name))
            .map((f) => {
            const overrideField = overrideFields.find((o) => o.name === f.name);
            const field = overrideField ?? f;
            return this.mapCell(field, rowData, extraClasses);
        });
    }
    mapCell(field, rowData, extraClasses = '') {
        const displayValue = rowData[field.name];
        const textValue = this.mapCellValue(field, displayValue);
        let fieldFormat = 'string';
        let classes = extraClasses;
        if (field.wordWrap) {
            classes += ` data-table-cell-wrap-${field.wordWrap.toLowerCase()}`;
        }
        if (field.header) {
            classes += ' govuk-table__header';
        }
        if (field.type === 'double' || field.type === 'long' || typeof displayValue === 'number') {
            fieldFormat = 'numeric';
        }
        if (fieldFormat === 'string' && displayValue && typeof displayValue === 'string') {
            const wordCount = displayValue.split(' ').length;
            if (wordCount > 10) {
                classes += ' data-table-cell-long-string';
            }
        }
        const isHtml = field.type === 'HTML';
        const cell = {
            fieldName: field.name,
            ...(isHtml ? { html: textValue } : { text: textValue }),
            format: fieldFormat,
            classes: classes.trim(),
        };
        return cell;
    }
    mapCellValue(field, cellData) {
        if (field.calculated) {
            return cellData;
        }
        switch (field.type) {
            case 'boolean':
                return this.mapBoolean(cellData);
            case 'date':
            case 'time':
                return this.mapDate(cellData);
            default:
                return cellData === undefined ? '' : cellData;
        }
    }
    mapHeader() {
        const WRAP_LENGTH = 20;
        return this.fields
            .filter((field) => this.columns.includes(field.name))
            .map((f) => {
            const { display, sortable, name } = f;
            const displayLength = display.length;
            const classes = displayLength > WRAP_LENGTH ? 'govuk-table__header--long' : '';
            if (this.reportQuery) {
                const { sortedAsc, sortColumn } = this.reportQuery;
                if (sortable) {
                    const isCurrentSort = name === sortColumn;
                    const nextAsc = isCurrentSort ? !sortedAsc : true;
                    let sortDirection = 'none';
                    if (isCurrentSort) {
                        sortDirection = sortedAsc ? 'ascending' : 'descending';
                    }
                    const updateQueryParams = {
                        sortColumn: f.name,
                        sortedAsc: String(nextAsc),
                        selectedPage: '1',
                    };
                    const url = urlHelper.mergeAndStringifyQuery(this.currentQueryParams ?? {}, updateQueryParams, this.fields);
                    const visuallyHiddenText = `. ${sortDirection === 'none' ? 'Not sorted' : `Sorted ${sortDirection}`}. Click to sort ${nextAsc ? 'Ascending' : 'Descending'}`;
                    return {
                        html: `<a ` +
                            `data-column="${f.name}" ` +
                            `aria-describedby="${f.name}"` +
                            `class="data-table-header-button data-table-header-button-sort-${sortDirection} ${classes}" ` +
                            `href="${url}"` +
                            `>${f.display}<span id=${f.name} class="govuk-visually-hidden">${visuallyHiddenText}</span></a>`,
                    };
                }
            }
            return {
                text: f.display,
                ...(classes && { classes }),
            };
        });
    }
    mapData(data) {
        const mappedHeaderSummary = this.mapSummary('table-header');
        const mappedTableData = this.mergeCells(data.map((rowData) => this.mapRow(rowData)));
        const mappedFooterSummary = this.mapSummary('table-footer');
        return mappedHeaderSummary.concat(mappedTableData).concat(mappedFooterSummary);
    }
    mergeCells(rows) {
        const mergeFieldNames = this.fields
            .filter((f) => f.mergeRows)
            .map((f) => f.name);
        if (mergeFieldNames.length === 0) {
            return rows;
        }
        const occurrences = {};
        mergeFieldNames.forEach((f) => {
            occurrences[f] = rows.reduce((accumulator, currentRow) => {
                const currentCell = this.getCellByFieldName(currentRow, f);
                let cellValue = '';
                if (currentCell) {
                    cellValue = currentCell.text || currentCell.html || '';
                }
                return {
                    ...accumulator,
                    [cellValue]: (accumulator[cellValue] ?? 0) + 1,
                };
            }, {});
        });
        return rows.map((row) => {
            let mergedRow = [...row];
            mergeFieldNames.forEach((mergeFieldName) => {
                const currentRowCell = this.getCellByFieldName(row, mergeFieldName);
                let cellValue;
                let occurrencesOfValue;
                if (currentRowCell && occurrences[mergeFieldName]) {
                    cellValue = currentRowCell.text || currentRowCell.html || '';
                    occurrencesOfValue = occurrences[mergeFieldName][cellValue];
                    switch (occurrencesOfValue) {
                        case -1:
                            mergedRow = mergedRow.filter((c) => c.fieldName !== mergeFieldName);
                            break;
                        case 1:
                            break;
                        default:
                            currentRowCell.rowspan = occurrencesOfValue;
                            occurrences[mergeFieldName][cellValue] = -1;
                    }
                }
            });
            return mergedRow;
        });
    }
    getCellByFieldName(row, fieldName) {
        return row.find((c) => c.fieldName === fieldName);
    }
    mapSummary(template) {
        if (this.reportSummaries[template]) {
            return this.reportSummaries[template].flatMap((reportSummary) => reportSummary.data.map((rowData) => this.mapRow(rowData, `dpr-report-summary-cell dpr-report-summary-cell-${template}`, reportSummary.fields)));
        }
        return [];
    }
    sort(data) {
        return this.appendSortKeyToData(data)
            .sort(this.sortKeyComparison())
            .map((d) => ({
            ...d,
        }));
    }
    sortKeyComparison() {
        return (a, b) => {
            const aValue = a.sortKey;
            const bValue = b.sortKey;
            if (aValue === bValue) {
                return 0;
            }
            if (aValue < bValue) {
                return -1;
            }
            return 1;
        };
    }
    appendSortKeyToData(data, fields = null) {
        const sortFields = fields || this.fields;
        return data.map((rowData) => {
            const sortKey = this.getSortKey(rowData, sortFields);
            return {
                ...rowData,
                sortKey,
            };
        });
    }
    mapNamesToFields(names) {
        return names.map((s) => this.fields.find((f) => f.name === s)).filter((n) => n !== undefined);
    }
    getSortKey(rowData, sortFields) {
        return sortFields
            .map((f) => {
            const value = rowData[f.name];
            if (value && this.dateMapper.isDate(value)) {
                return this.dateMapper.toDateString(value, 'iso');
            }
            return this.mapCellValue(f, value);
        })
            .join('-')
            .toLowerCase();
    }
    convertDataTableToHtml(dataTable) {
        const head = dataTable.head || [];
        const headers = head.map((h) => `<th scope='col' class='govuk-table__header'>${h.html ?? h.text}</th>`);
        const rows = dataTable.rows.map((r) => `<tr class='govuk-table__row'>${r
            .map((c) => `<td class='govuk-table__cell govuk-table__cell--${c.format} ${c.classes}'>${c.html ?? c.text}</td>`)
            .join('')}</tr>`);
        return ("<table class='govuk-table'>" +
            `<thead class='govuk-table__head'>${headers.join('')}</thead>` +
            `<tbody class='govuk-table__body'>${rows.join('')}</tbody>` +
            '</table>');
    }
    withHeaderOptions({ reportQuery, columns, interactive, }) {
        if (interactive && reportQuery) {
            return this.withHeaderSortOptions(reportQuery);
        }
        return this.withNoHeaderOptions(columns);
    }
    withHeaderSortOptions(reportQuery) {
        this.reportQuery = reportQuery;
        this.columns = reportQuery.columns;
        this.currentQueryParams = this.reportQuery.toRecordWithFilterPrefix();
        return this;
    }
    withNoHeaderOptions(columns) {
        this.columns = columns;
        return this;
    }
    buildTable(data) {
        const mappedData = this.mapData(this.sortData ? this.sort(data) : data);
        return {
            head: this.mapHeader(),
            rows: mappedData,
            rowCount: data.length,
            colCount: this.columns.length,
        };
    }
    withSummaries(reportSummaries) {
        this.reportSummaries = reportSummaries;
        return this;
    }
    withSortedData(sortData = true) {
        this.sortData = sortData;
        return this;
    }
}

exports.DataTableBuilder = DataTableBuilder;
exports.default = DataTableBuilder;
//# sourceMappingURL=DataTableBuilder.js.map
