"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzePreAggregateDerivedDimensionEligibility = exports.PreAggregateDerivedDimensionIneligibilityReason = void 0;
const exploreCompiler_1 = require("../../compiler/exploreCompiler");
const referenceLookup_1 = require("../../compiler/referenceLookup");
const item_1 = require("../../utils/item");
const lightdashSqlVariables_1 = require("../../utils/lightdashSqlVariables");
var PreAggregateDerivedDimensionIneligibilityReason;
(function (PreAggregateDerivedDimensionIneligibilityReason) {
    PreAggregateDerivedDimensionIneligibilityReason["CIRCULAR_DEPENDENCY"] = "circular_dependency";
    PreAggregateDerivedDimensionIneligibilityReason["COMPILATION_ERROR"] = "compilation_error";
    PreAggregateDerivedDimensionIneligibilityReason["MISSING_DEPENDENCY"] = "missing_dependency";
    PreAggregateDerivedDimensionIneligibilityReason["PARAMETER_REFERENCES"] = "parameter_references";
    PreAggregateDerivedDimensionIneligibilityReason["USER_ATTRIBUTES"] = "user_attributes";
})(PreAggregateDerivedDimensionIneligibilityReason || (exports.PreAggregateDerivedDimensionIneligibilityReason = PreAggregateDerivedDimensionIneligibilityReason = {}));
const mergeReferencedFieldIds = (current, next) => Array.from(new Set([...current, ...next]));
const hasParameterReferences = (dimension) => (dimension.parameterReferences?.length ?? 0) > 0;
const hasExplicitUserAttributeReference = (sql) => (0, lightdashSqlVariables_1.hasLightdashUserContextVariableReference)(sql);
const getReferencedDimensionForEligibility = ({ dimension, ref, tables, }) => {
    if (ref === 'TABLE') {
        return undefined;
    }
    const { refTable, refName } = (0, exploreCompiler_1.getParsedReference)(ref, dimension.table);
    return (0, referenceLookup_1.getReferencedDimension)(refTable, refName, tables);
};
const getIneligibleResult = ({ fieldId, reason, referencedDimensionFieldIds, }) => ({
    isEligible: false,
    reason,
    ineligibleDimensionFieldId: fieldId,
    referencedDimensionFieldIds,
});
const analyzeDimensionEligibility = ({ dimension, tables, state, }) => {
    const currentFieldId = (0, item_1.getItemId)(dimension);
    const cachedResult = state.cache.get(currentFieldId);
    if (cachedResult) {
        return cachedResult;
    }
    if (state.activeFieldIds.has(currentFieldId)) {
        return getIneligibleResult({
            fieldId: currentFieldId,
            reason: PreAggregateDerivedDimensionIneligibilityReason.CIRCULAR_DEPENDENCY,
            referencedDimensionFieldIds: [currentFieldId],
        });
    }
    state.activeFieldIds.add(currentFieldId);
    let result = {
        isEligible: true,
        referencedDimensionFieldIds: [currentFieldId],
    };
    try {
        if (dimension.compilationError) {
            result = getIneligibleResult({
                fieldId: currentFieldId,
                reason: PreAggregateDerivedDimensionIneligibilityReason.COMPILATION_ERROR,
                referencedDimensionFieldIds: [currentFieldId],
            });
            return result;
        }
        if (hasParameterReferences(dimension)) {
            result = getIneligibleResult({
                fieldId: currentFieldId,
                reason: PreAggregateDerivedDimensionIneligibilityReason.PARAMETER_REFERENCES,
                referencedDimensionFieldIds: [currentFieldId],
            });
            return result;
        }
        if (hasExplicitUserAttributeReference(dimension.sql)) {
            result = getIneligibleResult({
                fieldId: currentFieldId,
                reason: PreAggregateDerivedDimensionIneligibilityReason.USER_ATTRIBUTES,
                referencedDimensionFieldIds: [currentFieldId],
            });
            return result;
        }
        for (const ref of (0, exploreCompiler_1.getAllReferences)(dimension.sql)) {
            const referencedDimension = getReferencedDimensionForEligibility({
                dimension,
                ref,
                tables,
            });
            if (!referencedDimension) {
                if (ref === 'TABLE') {
                    // eslint-disable-next-line no-continue
                    continue;
                }
                result = getIneligibleResult({
                    fieldId: currentFieldId,
                    reason: PreAggregateDerivedDimensionIneligibilityReason.MISSING_DEPENDENCY,
                    referencedDimensionFieldIds: result.referencedDimensionFieldIds,
                });
                return result;
            }
            const referencedDimensionEligibility = analyzeDimensionEligibility({
                dimension: referencedDimension,
                tables,
                state,
            });
            const referencedDimensionFieldIds = mergeReferencedFieldIds(result.referencedDimensionFieldIds, referencedDimensionEligibility.referencedDimensionFieldIds);
            if (!referencedDimensionEligibility.isEligible) {
                result = {
                    ...referencedDimensionEligibility,
                    referencedDimensionFieldIds,
                };
                return result;
            }
            result = {
                isEligible: true,
                referencedDimensionFieldIds,
            };
        }
        return result;
    }
    finally {
        state.activeFieldIds.delete(currentFieldId);
        state.cache.set(currentFieldId, result);
    }
};
const analyzePreAggregateDerivedDimensionEligibility = ({ dimension, tables, }) => analyzeDimensionEligibility({
    dimension,
    tables,
    state: {
        activeFieldIds: new Set(),
        cache: new Map(),
    },
});
exports.analyzePreAggregateDerivedDimensionEligibility = analyzePreAggregateDerivedDimensionEligibility;
//# sourceMappingURL=dimensionEligibility.js.map