import { jsx as _jsx } from "react/jsx-runtime";
// (C) 2019-2026 GoodData Corporation
import { cloneDeep, isEmpty, set, tail } from "lodash-es";
import { bucketsAttributes, insightBuckets, } from "@gooddata/sdk-model";
import { BucketNames, VisualizationTypes } from "@gooddata/sdk-ui";
import { ATTRIBUTE, BUCKETS, DATE } from "../../../constants/bucket.js";
import { TREEMAP_SUPPORTED_PROPERTIES } from "../../../constants/supportedProperties.js";
import { MAX_METRICS_COUNT, getTreemapUiConfig } from "../../../constants/uiConfig.js";
import { configureOverTimeComparison, configurePercent } from "../../../utils/bucketConfig.js";
import { getAttributeItemsWithoutStacks, getMeasureItems, getStackItems, limitNumberOfMeasuresInBuckets, removeAllArithmeticMeasuresFromDerived, removeAllDerivedMeasures, sanitizeFilters, } from "../../../utils/bucketHelper.js";
import { hasNoStacksWithDate } from "../../../utils/bucketRules.js";
import { getReferencePointWithSupportedProperties } from "../../../utils/propertiesHelper.js";
import { removeSort } from "../../../utils/sort.js";
import { setTreemapUiConfig } from "../../../utils/uiConfigHelpers/treemapUiConfigHelper.js";
import { TreeMapConfigurationPanel } from "../../configurationPanels/TreeMapConfigurationPanel.js";
import { PluggableBaseChart } from "../baseChart/PluggableBaseChart.js";
import { addIntersectionFiltersToInsight, modifyBucketsAttributesForDrillDown, reverseAndTrimIntersection, } from "../drillDownUtil.js";
/**
 * PluggableTreemap
 *
 * ## Buckets
 *
 * | Name      | Id       | Accepts             |
 * |-----------|----------|---------------------|
 * | Measures  | measures | measures only       |
 * | ViewBy    | view     | attributes or dates |
 * | SegmentBy | segment  | attributes or dates |
 *
 * ### Bucket axioms
 *
 * - |Measures| ≥ 1
 * - |ViewBy| ≥ 1 ⇒ |Measures| ≤ 1
 * - |ViewBy| = 0 ⇒ |Measures| ≤ 20
 * - |Measures| ≥ 1 ⇒ |ViewBy| = 0
 * - |Measures| ≤ 1 ⇒ |ViewBy| ≤ 1
 * - |SegmentBy| ≤ 1
 *
 * ## Dimensions
 *
 * The PluggableTreemap always creates two dimensional execution.
 *
 * - |ViewBy| + |SegmentBy| = 1 ⇒ [[MeasureGroupIdentifier], [...ViewBy, ...SegmentBy]]
 * - |ViewBy| + |SegmentBy| != 1 ⇒ [[...ViewBy, ...SegmentBy], [MeasureGroupIdentifier]]
 *
 * ## Sorts
 *
 * Unless the user specifies otherwise, the sorts used by default are:
 *
 * - |ViewBy| ≥ 1 ∧ |SegmentBy| ≥ 1 ⇒ [attributeSort(ViewBy[0]), measureSort(...Measures)]
 */
export class PluggableTreemap extends PluggableBaseChart {
    constructor(props) {
        super(props);
        this.type = VisualizationTypes.TREEMAP;
        this.supportedPropertiesList = TREEMAP_SUPPORTED_PROPERTIES;
        this.initializeProperties(props.visualizationProperties);
    }
    getBucketMeasures(buckets = []) {
        const limitedBuckets = limitNumberOfMeasuresInBuckets(buckets, MAX_METRICS_COUNT, true);
        return getMeasureItems(limitedBuckets);
    }
    getBucketItemsWithMultipleDates(newReferencePoint) {
        const buckets = newReferencePoint?.buckets ?? [];
        let measures = this.getBucketMeasures(buckets);
        let stacks = getStackItems(buckets, [ATTRIBUTE, DATE]);
        const nonStackAttributes = getAttributeItemsWithoutStacks(buckets, [ATTRIBUTE, DATE]);
        const view = nonStackAttributes.slice(0, 1);
        if (nonStackAttributes.length > 0) {
            measures = getMeasureItems(limitNumberOfMeasuresInBuckets(buckets, 1));
        }
        if (nonStackAttributes.length > 1 && isEmpty(stacks)) {
            // first attribute is taken, find next available and put to stacks
            const attributesWithoutFirst = tail(nonStackAttributes);
            stacks = attributesWithoutFirst.slice(0, 1);
        }
        return { measures, view, stacks };
    }
    configureBuckets(newReferencePoint) {
        const { measures, view, stacks } = this.getBucketItemsWithMultipleDates(newReferencePoint);
        set(newReferencePoint, BUCKETS, [
            {
                localIdentifier: BucketNames.MEASURES,
                items: measures,
            },
            {
                localIdentifier: BucketNames.VIEW,
                items: view,
            },
            {
                localIdentifier: BucketNames.SEGMENT,
                items: stacks,
            },
        ]);
    }
    getTreemapUIConfig(referencePoint) {
        const buckets = referencePoint?.buckets;
        const nonStackAttributes = getAttributeItemsWithoutStacks(buckets, [ATTRIBUTE, DATE]);
        const measures = getMeasureItems(buckets);
        const uiConfig = getTreemapUiConfig(nonStackAttributes.length > 0, measures.length > 1);
        this.addMetricToFiltersIfEnabled(uiConfig);
        return uiConfig;
    }
    getExtendedReferencePoint(referencePoint) {
        const clonedReferencePoint = cloneDeep(referencePoint);
        let newReferencePoint = {
            ...clonedReferencePoint,
            uiConfig: this.getTreemapUIConfig(referencePoint),
        };
        newReferencePoint = removeAllArithmeticMeasuresFromDerived(newReferencePoint);
        newReferencePoint = removeAllDerivedMeasures(newReferencePoint);
        this.configureBuckets(newReferencePoint);
        newReferencePoint = setTreemapUiConfig(newReferencePoint, this.intl, this.type);
        newReferencePoint = configurePercent(newReferencePoint, false);
        newReferencePoint = configureOverTimeComparison(newReferencePoint);
        newReferencePoint = getReferencePointWithSupportedProperties(newReferencePoint, this.supportedPropertiesList);
        // set chart fill to solid if treemap is stacked
        if (!hasNoStacksWithDate(newReferencePoint.buckets)) {
            newReferencePoint = set(newReferencePoint, "properties.controls.chartFill", { type: "solid" });
        }
        newReferencePoint = removeSort(newReferencePoint);
        return Promise.resolve(sanitizeFilters(newReferencePoint, this.featureFlags?.enableImprovedAdFilters, referencePoint));
    }
    addFilters(source, drillConfig, event, backendSupportsElementUris) {
        const cutIntersection = reverseAndTrimIntersection(drillConfig, event.drillContext.intersection);
        return addIntersectionFiltersToInsight(source, cutIntersection, backendSupportsElementUris);
    }
    getInsightWithDrillDownApplied(source, drillDownContext, backendSupportsElementUris) {
        const withFilters = this.addFilters(source, drillDownContext.drillDefinition, drillDownContext.event, backendSupportsElementUris);
        return modifyBucketsAttributesForDrillDown(withFilters, drillDownContext.drillDefinition);
    }
    renderConfigurationPanel(insight, options) {
        const configPanelElement = this.getConfigPanelElement();
        if (configPanelElement) {
            const buckets = insightBuckets(insight, BucketNames.SEGMENT);
            const isStackedTreemap = bucketsAttributes(buckets).length > 0;
            const panelConfig = {
                supportsAttributeHierarchies: this.backendCapabilities.supportsAttributeHierarchies,
                supportsChartFill: options.supportsChartFill,
                isChartFillDisabled: isStackedTreemap,
            };
            this.renderFun(_jsx(TreeMapConfigurationPanel, { locale: this.locale, references: this.references, properties: this.visualizationProperties, propertiesMeta: this.propertiesMeta, insight: insight, colors: this.colors, pushData: this.handlePushData, type: this.type, isError: this.getIsError(), isLoading: this.isLoading, featureFlags: this.featureFlags, panelConfig: panelConfig, configurationPanelRenderers: options.custom?.configurationPanelRenderers }), configPanelElement);
        }
    }
}
//# sourceMappingURL=PluggableTreemap.js.map