"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.derivePivotConfigurationFromChart = derivePivotConfigurationFromChart;
const tslib_1 = require("tslib");
/**
 * Derives pivot configuration from a saved chart's configuration and metric query
 * This enables consistent pivoting across all chart types
 */
const field_1 = require("../types/field");
const savedCharts_1 = require("../types/savedCharts");
const assertUnreachable_1 = tslib_1.__importDefault(require("../utils/assertUnreachable"));
const types_1 = require("../visualizations/types");
const utils_1 = require("./utils");
function getSortByForPivotConfiguration(partialPivot, metricQuery) {
    const { groupByColumns, indexColumn, valuesColumns } = partialPivot;
    const sortBy = metricQuery.sorts
        .map((sort) => {
        const isGroupByColumn = groupByColumns?.some((col) => col.reference === sort.fieldId);
        const isIndexColumn = (0, utils_1.normalizeIndexColumns)(indexColumn).some((col) => col.reference === sort.fieldId);
        const isValueColumn = valuesColumns?.some((col) => col.reference === sort.fieldId);
        // Include sort if the field is present in any part of the pivot configuration
        if (isGroupByColumn || isIndexColumn || isValueColumn) {
            return {
                reference: sort.fieldId,
                direction: sort.descending
                    ? types_1.SortByDirection.DESC
                    : types_1.SortByDirection.ASC,
                nullsFirst: sort.nullsFirst,
            };
        }
        return undefined;
    })
        .filter((sort) => sort !== undefined);
    if (sortBy.length === 0) {
        return undefined;
    }
    return sortBy;
}
const getIndexColumn = (groupByColumns, valuesColumns, fields, metricQuery, xField) => {
    const groupByColumnsReferences = groupByColumns?.map((c) => c.reference) ?? [];
    const valuesColumnsReferences = valuesColumns?.map((c) => c.reference) ?? [];
    const sortFieldIds = new Set(metricQuery.sorts.map((s) => s.fieldId));
    // Find any columns that are not groupBy or value columns (these become index columns)
    // Table calculations are only included if they are the xField (used as the x-axis dimension)
    // or if they are used in sorting. Otherwise we don't want to include them as multiple
    // index columns cause multiple series.
    const tableCalcNames = (metricQuery.tableCalculations || [])
        .filter((tc) => tc.name === xField || sortFieldIds.has(tc.name))
        .map((tc) => tc.name);
    const indexColumnNames = [
        ...metricQuery.dimensions,
        ...metricQuery.metrics,
        ...tableCalcNames,
    ].filter((dim) => !groupByColumnsReferences.includes(dim) &&
        !valuesColumnsReferences.includes(dim));
    return indexColumnNames
        .map((dim) => {
        const field = fields[dim];
        if (!field)
            return undefined;
        if ((0, field_1.isDimension)(field)) {
            return {
                reference: dim,
                type: (0, types_1.getColumnAxisType)(field.type),
            };
        }
        if ((0, field_1.isCustomDimension)(field)) {
            // For SQL custom dimensions, use provided dimensionType; otherwise default to CATEGORY
            const axisType = field.type === field_1.CustomDimensionType.SQL
                ? (0, types_1.getColumnAxisType)(field.dimensionType)
                : (0, types_1.getColumnAxisType)(field_1.DimensionType.STRING);
            return {
                reference: dim,
                type: axisType,
            };
        }
        // Table calculations can be used in x axis, therefore we need to handle them here as well when they're not a value column
        if ((0, field_1.isTableCalculation)(field)) {
            return {
                reference: dim,
                type: (0, types_1.getTableCalculationAxisType)(field.type ?? field_1.TableCalculationType.NUMBER),
            };
        }
        return undefined;
    })
        .filter((col) => col !== undefined);
};
function getTablePivotConfiguration(savedChart, metricQuery, fields) {
    const { chartConfig, pivotConfig } = savedChart;
    if (chartConfig.type !== savedCharts_1.ChartType.TABLE) {
        throw new Error('Chart is not a table');
    }
    if (!pivotConfig) {
        return undefined;
    }
    // Create value columns for each metric and table calculation
    const valuesColumns = [
        ...metricQuery.metrics.map((metric) => ({
            reference: metric,
            aggregation: types_1.VizAggregationOptions.ANY,
        })),
        ...(metricQuery.tableCalculations || []).map((tc) => ({
            reference: tc.name,
            aggregation: types_1.VizAggregationOptions.ANY,
        })),
    ].filter((col) => metricQuery.dimensions.includes(col.reference) ||
        metricQuery.metrics.includes(col.reference) ||
        (metricQuery.tableCalculations || []).some((tc) => tc.name === col.reference));
    const pivotColumns = pivotConfig.columns || [];
    // Group by columns are the pivot dimensions
    const groupByColumns = pivotColumns
        .map((col) => ({
        reference: col,
    }))
        .filter((col) => metricQuery.dimensions.includes(col.reference));
    // Find columns that are not groupBy or value columns (these become index columns)
    const indexColumn = getIndexColumn(groupByColumns, valuesColumns, fields, metricQuery);
    const partialPivotConfiguration = {
        indexColumn,
        valuesColumns,
        groupByColumns,
    };
    const pivotConfiguration = {
        ...partialPivotConfiguration,
        sortBy: getSortByForPivotConfiguration(partialPivotConfiguration, metricQuery),
    };
    return pivotConfiguration;
}
function getCartesianPivotConfiguration(savedChart, metricQuery, fields) {
    const { chartConfig, pivotConfig } = savedChart;
    if (chartConfig.type !== savedCharts_1.ChartType.CARTESIAN) {
        throw new Error('Chart is not a Cartesian chart');
    }
    if (!(0, savedCharts_1.isCartesianChartConfig)(chartConfig.config)) {
        throw new Error('Invalid cartesian chart config - no eCharts config');
    }
    const { layout: { xField, yField }, } = chartConfig.config;
    if (pivotConfig?.columns && xField && yField) {
        // Extract and validate pivot columns
        const groupByColumns = pivotConfig.columns
            .map((pv) => ({
            reference: pv,
        }))
            .filter((col) => metricQuery.dimensions.includes(col.reference));
        // Extract value columns (metrics and table calculations from yField)
        const valuesColumns = yField
            .map((yf) => ({
            reference: yf,
            aggregation: types_1.VizAggregationOptions.ANY,
        }))
            .filter((col) => metricQuery.dimensions.includes(col.reference) ||
            metricQuery.metrics.includes(col.reference) ||
            (metricQuery.tableCalculations || []).some((tc) => tc.name === col.reference));
        // Find columns that are not groupBy or value columns (these become index columns)
        const indexColumn = getIndexColumn(groupByColumns, valuesColumns, fields, metricQuery, xField);
        const partialPivotConfiguration = {
            indexColumn,
            valuesColumns,
            groupByColumns,
        };
        const pivotConfiguration = {
            ...partialPivotConfiguration,
            sortBy: getSortByForPivotConfiguration(partialPivotConfiguration, metricQuery),
        };
        return pivotConfiguration;
    }
    return undefined;
}
function isValid(pivotConfiguration) {
    const { groupByColumns, valuesColumns, indexColumn } = pivotConfiguration;
    const indexColumns = (0, utils_1.normalizeIndexColumns)(indexColumn);
    if (indexColumns.length === 0) {
        return false;
    }
    if (valuesColumns.length === 0) {
        return false;
    }
    if (!groupByColumns || groupByColumns.length === 0) {
        return false;
    }
    // Validate that no groupBy column is also part of the index columns
    const indexRefs = new Set(indexColumns.map((c) => c.reference));
    const overlapping = groupByColumns
        .map((c) => c.reference)
        .filter((ref) => indexRefs.has(ref));
    if (overlapping.length > 0) {
        return false;
    }
    return true;
}
function derivePivotConfigurationFromChart(savedChart, metricQuery, fields) {
    const { chartConfig } = savedChart;
    const { type } = chartConfig;
    let newConfig;
    switch (type) {
        case savedCharts_1.ChartType.TABLE:
            newConfig = getTablePivotConfiguration(savedChart, metricQuery, fields);
            break;
        case savedCharts_1.ChartType.CARTESIAN:
            newConfig = getCartesianPivotConfiguration(savedChart, metricQuery, fields);
            break;
        case savedCharts_1.ChartType.PIE:
        case savedCharts_1.ChartType.FUNNEL:
        case savedCharts_1.ChartType.TREEMAP:
        case savedCharts_1.ChartType.GAUGE:
        case savedCharts_1.ChartType.CUSTOM:
        case savedCharts_1.ChartType.BIG_NUMBER:
        case savedCharts_1.ChartType.MAP:
            newConfig = undefined;
            break;
        default:
            return (0, assertUnreachable_1.default)(type, `Unknown chart type ${type}`);
    }
    // Validate pivot configuration
    if (newConfig && isValid(newConfig)) {
        return newConfig;
    }
    return undefined;
}
//# sourceMappingURL=derivePivotConfigFromChart.js.map