import dayjs from 'dayjs';
import weekOfYear from '../../../_virtual/weekOfYear.js';
import { apiDateToUi } from '../../utils/dateHelper.js';
import DatasetHelper from '../../utils/Dashboards/VisualisationDatasetHelper.js';
import { mapUnitToSymbol } from '../../utils/Dashboards/VisualisationUnitHelper.js';
import DashboardListUtils from '../_dashboards/dashboard-list/utils.js';
import { DashboardVisualisationType } from '../_dashboards/dashboard-visualisation/types.js';
import { Granularity } from '../_inputs/granular-date-range/types.js';
import { BarTimeseriesChart } from './chart/bar-timeseries/BarTimeseriesChart.js';
import { BarChart } from './chart/bar/BarChart.js';
import { DoughnutChart } from './chart/doughnut/DoughnutChart.js';
import { HeatmapChart } from './chart/heatmap/HeatmapChart.js';
import { LineTimeseriesChart } from './chart/line-timeseries/LineTimeseriesChart.js';
import { LineChart } from './chart/line/LineChart.js';

dayjs.extend(weekOfYear);
const createChart = (chartDefinition, rawData, type) => {
    let table;
    let chart;
    let details;
    const { dataSetRows, snapshotData } = getDataForSnapshotCharts(chartDefinition, rawData);
    if (dataSetRows.length) {
        switch (type) {
            case DashboardVisualisationType.BAR:
                chart = new BarChart().withDefinition(chartDefinition).withData(snapshotData).build();
                break;
            case DashboardVisualisationType.DONUT:
                chart = new DoughnutChart().withDefinition(chartDefinition).withData(snapshotData).build();
                break;
            case DashboardVisualisationType.LINE:
                chart = new LineChart().withDefinition(chartDefinition).withData(snapshotData).build();
                break;
        }
        table = createSnapshotTable(chartDefinition, dataSetRows);
        details = getChartDetails(chartDefinition, dataSetRows);
    }
    return {
        details,
        table,
        chart,
    };
};
const createTimeseriesCharts = (chartDefinition, rawData, type, query, partialDate) => {
    let table;
    let chart;
    let details;
    let granularity = Granularity.DAILY;
    if (query) {
        Object.keys(query).forEach((key) => {
            if (key.includes('granularity')) {
                granularity = query[key];
            }
        });
    }
    const { latestData, dataSetRows, timeseriesData } = getDataForTimeseriesCharts(chartDefinition, rawData);
    if (dataSetRows.length) {
        switch (type) {
            case DashboardVisualisationType.MATRIX_TIMESERIES:
                chart = new HeatmapChart()
                    .withDefinition(chartDefinition)
                    .withGranularity(granularity)
                    .withData(timeseriesData)
                    .build();
                break;
            case DashboardVisualisationType.LINE_TIMESERIES:
                chart = new LineTimeseriesChart()
                    .withDefinition(chartDefinition)
                    .withData(timeseriesData)
                    .withPartialDate(partialDate)
                    .build();
                break;
            case DashboardVisualisationType.BAR_TIMESERIES:
                chart = new BarTimeseriesChart()
                    .withDefinition(chartDefinition)
                    .withData(timeseriesData)
                    .withPartialDate(partialDate)
                    .build();
                break;
        }
        table = createTimeseriesTable(chartDefinition, timeseriesData);
        details = getChartDetails(chartDefinition, latestData, true);
    }
    return {
        details,
        table,
        chart,
    };
};
const getDataForSnapshotCharts = (chartDefinition, rawData) => {
    const data = DatasetHelper.getLastestDataset(rawData);
    const dataSetRows = DatasetHelper.getDatasetRows(chartDefinition, data);
    const snapshotData = DatasetHelper.filterRowsByDisplayColumns(chartDefinition, dataSetRows, true);
    return {
        dataSetRows,
        snapshotData,
    };
};
const getDataForTimeseriesCharts = (chartDefinition, rawData) => {
    const latestData = DatasetHelper.getLastestDataset(rawData);
    const dataSetRows = DatasetHelper.getDatasetRows(chartDefinition, rawData);
    const timeseriesData = DatasetHelper.filterRowsByDisplayColumns(chartDefinition, dataSetRows, true);
    return {
        latestData,
        dataSetRows,
        timeseriesData,
    };
};
const getChartDetails = (chartDefinition, data, timeseries = false) => {
    const meta = [];
    const headlines = createHeadlines(chartDefinition, data, timeseries);
    const rawDate = `${data[0]['ts'].raw}`;
    if (rawDate) {
        meta.push({
            label: 'Values for:',
            value: apiDateToUi(rawDate) || rawDate,
        });
    }
    return {
        meta,
        headlines,
    };
};
const createHeadlines = (chartDefinition, data, timeseries = false) => {
    const headlines = [];
    const { columns } = chartDefinition;
    const { measures } = columns;
    const isListChart = !!measures.find((col) => col.axis);
    let headline;
    let headlineColumn;
    let value;
    let label = '';
    if (timeseries) {
        headlineColumn = measures.find((col) => col.type !== 'date');
        if (headlineColumn) {
            const { id } = headlineColumn;
            const { raw } = data[0][id];
            const rawDate = `${data[0]['ts'].raw}`;
            if (rawDate) {
                label = apiDateToUi(rawDate) || rawDate;
            }
            value = raw ? Number(raw) : undefined;
            if (value) {
                headline = {
                    label,
                    value,
                };
            }
        }
    }
    else {
        headlineColumn = !isListChart ? measures[0] : measures.find((col) => col.axis && col.axis === 'y');
        if (headlineColumn) {
            const display = headlineColumn.display?.toLowerCase();
            label = display ? `Total ${display}` : 'Total';
            value = data.reduce((acc, d) => {
                if (headlineColumn) {
                    const { id } = headlineColumn;
                    const { raw } = d[id];
                    if (raw) {
                        return acc + Number(raw);
                    }
                }
                return acc;
            }, 0);
            headline = {
                label,
                value,
            };
        }
    }
    if (headline)
        headlines.push(headline);
    return headlines;
};
const mapTableHead = (headerColumns) => {
    return headerColumns.map((column) => {
        const unitSymbol = mapUnitToSymbol(column.unit);
        const headText = unitSymbol ? `${column.display} (${unitSymbol})` : column.display;
        return { text: headText || '' };
    });
};
const createSnapshotTable = (chartDefinition, data) => {
    const { columns } = chartDefinition;
    const { measures } = columns;
    const keys = columns.keys || [];
    const head = mapTableHead([...keys, ...measures]);
    const filteredRowData = DatasetHelper.filterRowsByDisplayColumns(chartDefinition, data, true);
    const rows = DashboardListUtils.createTableRows(filteredRowData);
    return {
        head,
        rows,
    };
};
/**
 * Creates the a table representation for a timeseries chart
 * - ensures the Date column is always at index 0 when there are multiple rows
 *
 * @param {components['schemas']['DashboardVisualisationDefinition']} chartDefinition
 * @param {DashboardDataResponse[]} timeseriesData
 * @return {*}  {MoJTable}
 */
const createTimeseriesTable = (chartDefinition, timeseriesData) => {
    const { columns } = chartDefinition;
    const { keys, measures = [] } = columns;
    const safeKeys = keys ?? [];
    let flatTimeseriesData = timeseriesData.flat();
    let tableColumns;
    if (timeseriesData.length > 1) {
        const dateMeasures = measures.filter((m) => m.type === 'date');
        if (dateMeasures.length !== 1) {
            throw new Error('Multi-timeseries tables require exactly one date measure');
        }
        const [dateColumn] = dateMeasures;
        const valueColumns = measures.filter((m) => m.type !== 'date');
        tableColumns = [dateColumn, ...safeKeys, ...valueColumns];
    }
    else {
        flatTimeseriesData = DatasetHelper.filterRowsByDisplayColumns(chartDefinition, flatTimeseriesData);
        tableColumns = measures;
    }
    const head = mapTableHead(tableColumns);
    const rows = DashboardListUtils.createTableRows(flatTimeseriesData, tableColumns);
    return { head, rows };
};
var ChartUtils = {
    createChart,
    createTimeseriesCharts,
};

export { createChart, createTimeseriesCharts, ChartUtils as default };
//# sourceMappingURL=utils.js.map
