"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sortedItemsForYAxis = exports.sortedItemsForXAxis = exports.canApplyFormattingToCustomMetric = exports.replaceDimensionInExplore = exports.isMetricWithDateValue = exports.getEffectiveItemType = exports.isDateItem = exports.getItemIcon = exports.isStringDimension = exports.getItemLabel = exports.getItemLabelWithoutTableName = exports.getItemId = exports.isNumericType = void 0;
exports.getItemType = getItemType;
exports.isNumericItem = isNumericItem;
const errors_1 = require("../types/errors");
const field_1 = require("../types/field");
const metricQuery_1 = require("../types/metricQuery");
const isNumericType = (type) => {
    const numericTypes = [
        field_1.TableCalculationType.NUMBER,
        field_1.DimensionType.NUMBER,
        field_1.MetricType.NUMBER,
        field_1.MetricType.PERCENTILE,
        field_1.MetricType.MEDIAN,
        field_1.MetricType.AVERAGE,
        field_1.MetricType.COUNT,
        field_1.MetricType.COUNT_DISTINCT,
        field_1.MetricType.SUM,
        field_1.MetricType.SUM_DISTINCT,
        field_1.MetricType.AVERAGE_DISTINCT,
        field_1.MetricType.MIN,
        field_1.MetricType.MAX,
        field_1.MetricType.PERCENT_OF_PREVIOUS,
        field_1.MetricType.PERCENT_OF_TOTAL,
        field_1.MetricType.RUNNING_TOTAL,
    ];
    return numericTypes.includes(type);
};
exports.isNumericType = isNumericType;
const getItemId = (item) => {
    if (!item) {
        // This should never happen based on the type system, but it is happening. Throwing an error so we can investigate.
        throw new errors_1.ParameterError('Item is undefined');
    }
    if ((0, field_1.isCustomDimension)(item)) {
        return item.id;
    }
    if ((0, field_1.isTableCalculation)(item)) {
        return item.name;
    }
    // dimension or metric or additional metric or field
    return `${item.table}_${item.name.replaceAll('.', '__')}`;
};
exports.getItemId = getItemId;
const getItemLabelWithoutTableName = (item) => {
    if ((0, field_1.isCustomDimension)(item))
        return item.name;
    return (0, field_1.isField)(item) || (0, metricQuery_1.isAdditionalMetric)(item)
        ? `${item.label}`
        : item.displayName;
};
exports.getItemLabelWithoutTableName = getItemLabelWithoutTableName;
const getItemLabel = (item) => ((0, field_1.isField)(item) ? `${item.tableLabel} ` : '') +
    (0, exports.getItemLabelWithoutTableName)(item);
exports.getItemLabel = getItemLabel;
function getItemType(item) {
    if ((0, field_1.isDimension)(item) || (0, field_1.isMetric)(item)) {
        return item.type;
    }
    if ((0, field_1.isCustomSqlDimension)(item)) {
        return item.dimensionType;
    }
    if ((0, field_1.isCustomBinDimension)(item)) {
        return field_1.DimensionType.STRING;
    }
    if ((0, field_1.isTableCalculation)(item)) {
        return item.type ?? field_1.TableCalculationType.NUMBER;
    }
    if ((0, metricQuery_1.isAdditionalMetric)(item)) {
        return item.type;
    }
    return field_1.DimensionType.STRING;
}
function isNumericItem(item) {
    if (!item) {
        return false;
    }
    return (0, exports.isNumericType)(getItemType(item));
}
const isStringDimension = (item) => {
    if (!item) {
        return false;
    }
    return (((0, field_1.isDimension)(item) || (0, field_1.isCustomDimension)(item)) &&
        getItemType(item) === field_1.DimensionType.STRING);
};
exports.isStringDimension = isStringDimension;
const getItemIcon = (item) => {
    if ((0, field_1.isCustomDimension)(item))
        return 'tag';
    if ((0, field_1.isField)(item)) {
        return (0, field_1.isDimension)(item) ? 'tag' : 'numerical';
    }
    return 'function';
};
exports.getItemIcon = getItemIcon;
const isDateItem = (item) => {
    if (!item) {
        return false;
    }
    if ((0, field_1.isField)(item) || (0, metricQuery_1.isAdditionalMetric)(item)) {
        const dateTypes = [
            field_1.DimensionType.DATE,
            field_1.MetricType.DATE,
            field_1.DimensionType.TIMESTAMP,
            field_1.MetricType.TIMESTAMP,
        ];
        return dateTypes.includes(item.type);
    }
    return true;
};
exports.isDateItem = isDateItem;
/**
 * Gets the effective type for formatting purposes.
 * For metrics that return date/timestamp values (MIN/MAX on date dimensions),
 * returns the underlying dimension type instead of the metric type.
 *
 * @param item - The item to get the effective type for
 * @param itemsMap - Optional itemsMap to look up dimension types
 * @returns The effective type for formatting (DimensionType, MetricType, or TableCalculationType)
 */
const getEffectiveItemType = (item, itemsMap) => {
    if (!item) {
        return undefined;
    }
    // For metrics with MIN/MAX on date dimensions, return the dimension type
    if ((0, field_1.isMetric)(item) &&
        (item.type === field_1.MetricType.MIN || item.type === field_1.MetricType.MAX) &&
        item.dimensionReference &&
        itemsMap) {
        const dimension = itemsMap[item.dimensionReference];
        if (dimension && (0, field_1.isDimension)(dimension)) {
            if (dimension.type === field_1.DimensionType.DATE ||
                dimension.type === field_1.DimensionType.TIMESTAMP) {
                return dimension.type;
            }
        }
    }
    return getItemType(item);
};
exports.getEffectiveItemType = getEffectiveItemType;
/**
 * Checks if a metric returns a date/timestamp value.
 * This is true when:
 * 1. The metric type is directly DATE or TIMESTAMP
 * 2. The metric type is MIN or MAX and the underlying dimension (via dimensionReference) is a date/timestamp
 *
 * @param item - The metric to check
 * @param itemsMap - Optional itemsMap to look up the dimension type from dimensionReference
 * @returns true if the metric returns a date/timestamp value
 */
const isMetricWithDateValue = (item, itemsMap) => {
    if (!item || !(0, field_1.isMetric)(item)) {
        return false;
    }
    const effectiveType = (0, exports.getEffectiveItemType)(item, itemsMap);
    const dateTypes = [
        field_1.DimensionType.DATE,
        field_1.DimensionType.TIMESTAMP,
        field_1.MetricType.DATE,
        field_1.MetricType.TIMESTAMP,
    ];
    return dateTypes.includes(effectiveType);
};
exports.isMetricWithDateValue = isMetricWithDateValue;
const replaceDimensionInExplore = (explore, dimension) => ({
    ...explore,
    tables: {
        ...explore.tables,
        [dimension.table]: {
            ...explore.tables[dimension.table],
            dimensions: {
                ...explore.tables[dimension.table].dimensions,
                [dimension.name]: dimension,
            },
        },
    },
});
exports.replaceDimensionInExplore = replaceDimensionInExplore;
const canApplyFormattingToCustomMetric = (item, customMetricType) => isNumericItem(item) ||
    [field_1.MetricType.COUNT_DISTINCT, field_1.MetricType.COUNT].includes(customMetricType);
exports.canApplyFormattingToCustomMetric = canApplyFormattingToCustomMetric;
/**
 * When selecting a field for the x axis,
 * we want to prioritize dimensions and date items
 * over metrics and table calculations
 * Used in CustomVisTemplate.tsx
 */
const sortedItemsForXAxis = (itemsMap) => Object.values(itemsMap || {}).sort((a, b) => {
    const getPriority = (item) => {
        if ((0, field_1.isDimension)(item) && (0, exports.isDateItem)(item))
            return 1;
        if ((0, field_1.isDimension)(item))
            return 2;
        if ((0, field_1.isCustomDimension)(item))
            return 3;
        if ((0, field_1.isMetric)(item))
            return 4;
        return 5; // everything else
    };
    return getPriority(a) - getPriority(b);
});
exports.sortedItemsForXAxis = sortedItemsForXAxis;
/**
 * When selecting a field for the y axis (and color/size values),
 * we want to prioritize numeric metrics and table calculations
 * over dimensions
 */
const sortedItemsForYAxis = (itemsMap) => Object.values(itemsMap || {}).sort((a, b) => {
    const getPriorityForY = (item) => {
        if ((0, field_1.isMetric)(item) && (0, exports.isNumericType)(item.type))
            return 1;
        if ((0, field_1.isMetric)(item))
            return 2;
        if ((0, field_1.isTableCalculation)(item))
            return 3;
        return 4; // everything else
    };
    return getPriorityForY(a) - getPriorityForY(b);
});
exports.sortedItemsForYAxis = sortedItemsForYAxis;
//# sourceMappingURL=item.js.map