import { jsx as _jsx } from "react/jsx-runtime";
// (C) 2024-2026 GoodData Corporation
import { cloneDeep, compact, omit } from "lodash-es";
import { areObjRefsEqual, insightBucket, insightBuckets, insightProperties, insightSetBuckets, } from "@gooddata/sdk-model";
import { BucketNames } from "@gooddata/sdk-ui";
import { ColorUtils, CoreRepeater, constructRepeaterBuckets, constructRepeaterDimensions, updateConfigWithSettings, } from "@gooddata/sdk-ui-charts";
import { DASHBOARDS_ENVIRONMENT } from "../../../constants/properties.js";
import { REPEATER_SUPPORTER_PROPERTIES_LIST } from "../../../constants/supportedProperties.js";
import { defaultImprovedFilters } from "../../../constants/uiConfig.js";
import { InvalidBucketsSdkError, InvalidColumnsSdkError, } from "../../../interfaces/Visualization.js";
import { cloneBucketItem, getMainRowAttribute, sanitizeFilters } from "../../../utils/bucketHelper.js";
import { getValidProperties } from "../../../utils/colors.js";
import { getSupportedPropertiesControls } from "../../../utils/propertiesHelper.js";
import { configRepeaterBuckets, getDefaultRepeaterUiConfig, setRepeaterUiConfig, } from "../../../utils/uiConfigHelpers/repeaterUiConfigHelper.js";
import { RepeaterConfigurationPanel } from "../../configurationPanels/RepeaterConfigurationPanel.js";
import { AbstractPluggableVisualization } from "../AbstractPluggableVisualization.js";
/**
 * PluggableRepeater
 *
 * ## Buckets
 *
 * | Name      | Id       -| Accepts              |
 * |-----------|-----------|----------------------|
 * | Attribute | attribute | attribute only       |
 * | Columns   | columns   | attribute or measure |
 * | ViewBy    | view      | attribute or date    |
 *
 *
 * ### Bucket axioms
 *
 * - |Attribute| = 1
 * - |Columns| ≥ 1
 * - |ViewBy| ≤ 1
 *
 * ## Dimensions
 *
 * The PluggableRepeater creates one or two dimensional execution, based on  the buckets.
 *
 * With main attribute and column attributes only:
 * - [[Attribute, ...ColumnAttributes]]
 * With main attribute, column attributes and viewBy:
 * - [[Attribute, ...ColumnAttributes], [ViewBy]]
 * With main attribute and column attributes and measures:
 * - [[Attribute, ...ColumnAttributes], [MeasureGroupIdentifier]]
 * With main attribute, column attributes and measures, and viewBy:
 * - [[Attribute, ...ColumnAttributes], [ViewBy, MeasureGroupIdentifier]]
 *
 */
export class PluggableRepeater extends AbstractPluggableVisualization {
    environment;
    renderFun;
    unmountFun;
    colors;
    constructor(props) {
        super(props);
        this.environment = props.environment;
        this.renderFun = props.renderFun;
        this.unmountFun = props.unmountFun;
        this.supportedPropertiesList = REPEATER_SUPPORTER_PROPERTIES_LIST;
        this.initializeProperties(props.visualizationProperties);
    }
    unmount() {
        this.unmountFun([this.getElement(), this.getConfigPanelElement()]);
    }
    getExtendedReferencePoint = async (referencePoint) => {
        const referencePointCloned = cloneDeep(referencePoint);
        const uiConfig = getDefaultRepeaterUiConfig();
        if (this.featureFlags?.enableImprovedAdFilters && uiConfig.buckets?.["filters"]) {
            uiConfig.buckets["filters"] = defaultImprovedFilters.filters;
        }
        let newReferencePoint = {
            ...referencePointCloned,
            uiConfig,
        };
        newReferencePoint = configRepeaterBuckets(newReferencePoint);
        newReferencePoint = setRepeaterUiConfig(newReferencePoint, this.intl);
        return Promise.resolve(sanitizeFilters(newReferencePoint, this.featureFlags?.enableImprovedAdFilters, referencePointCloned));
    };
    getExecution(options, insight, executionFactory) {
        const { dateFormat } = options;
        const dimensions = this.getRepeaterDimensions(insight);
        const attributeBucket = insightBucket(insight, BucketNames.ATTRIBUTE);
        const viewBucket = insightBucket(insight, BucketNames.VIEW);
        const rowAttribute = attributeBucket?.items[0];
        const columnsBucket = insightBucket(insight, BucketNames.COLUMNS);
        const extendedConfig = this.getExtendedConfig(options, insight);
        const sanitizedBuckets = constructRepeaterBuckets(rowAttribute, columnsBucket.items, viewBucket?.items?.[0], extendedConfig?.inlineVisualizations);
        const insightWithSanitizedBuckets = insightSetBuckets(insight, sanitizedBuckets);
        return executionFactory
            .forInsight(insightWithSanitizedBuckets)
            .withDimensions(...dimensions)
            .withDateFormat(dateFormat);
    }
    getBucketsToUpdate(currentReferencePoint, nextReferencePoint) {
        const currentRefencePointClone = cloneDeep(currentReferencePoint);
        const nextReferencePointClone = cloneDeep(nextReferencePoint);
        const currentBuckets = currentRefencePointClone?.buckets ?? [];
        const currentRowAttribute = getMainRowAttribute(currentBuckets);
        const nextBuckets = nextReferencePointClone?.buckets ?? [];
        const nextRowAttribute = getMainRowAttribute(nextBuckets);
        const rowAttributeWasEmpty = !currentRowAttribute && nextRowAttribute;
        const rowAttributeWasSwapped = currentRowAttribute &&
            nextRowAttribute &&
            !currentRowAttribute.displayForms?.some((currentDf) => areObjRefsEqual(currentDf.ref, nextRowAttribute.dfRef));
        if (rowAttributeWasEmpty || rowAttributeWasSwapped) {
            // clone the row attribute
            return [cloneBucketItem(nextRowAttribute)];
        }
        if (currentRowAttribute && !nextRowAttribute) {
            // empty all column attributes
            return [];
        }
        // do nothing
        return undefined;
    }
    getRepeaterDimensions(insight) {
        const buckets = insightBuckets(insight);
        return constructRepeaterDimensions(buckets);
    }
    insightHasColumns(insight) {
        const bucket = insightBucket(insight, BucketNames.COLUMNS);
        return (bucket?.items?.length ?? 0) > 0;
    }
    insightHasRows(insight) {
        const bucket = insightBucket(insight, BucketNames.ATTRIBUTE);
        return (bucket?.items?.length ?? 0) > 0;
    }
    mergeDerivedBucketItems(_referencePoint, bucket, newDerivedBucketItems) {
        let result;
        if (bucket.localIdentifier === BucketNames.ATTRIBUTE) {
            result = bucket.items;
        }
        if (bucket.localIdentifier === BucketNames.VIEW) {
            result = [];
        }
        if (newDerivedBucketItems.length === 0) {
            result = [];
        }
        // remove all existing attributes as they should disappear when cloning the row attribute
        const itemsWithoutAttributes = bucket.items.filter((item) => item.type !== "attribute");
        if (result !== undefined) {
            return result;
        }
        return [...newDerivedBucketItems, ...itemsWithoutAttributes];
    }
    checkBeforeRender(insight) {
        super.checkBeforeRender(insight);
        if (!this.insightHasColumns(insight)) {
            throw new InvalidColumnsSdkError();
        }
        if (!this.insightHasRows(insight)) {
            throw new InvalidBucketsSdkError();
        }
        return true;
    }
    initializeProperties(visualizationProperties) {
        const controls = visualizationProperties?.controls;
        const supportedProperties = getSupportedPropertiesControls(controls, this.supportedPropertiesList);
        const initialProperties = {
            supportedProperties: { controls: supportedProperties },
        };
        this.handlePushData({
            initialProperties,
        });
    }
    onColumnResized = (columnWidths) => {
        const properties = this.visualizationProperties ?? {};
        const supportedProperties = {
            ...getSupportedPropertiesControls(properties?.controls, this.supportedPropertiesList),
            columnWidths,
        };
        this.visualizationProperties = supportedProperties;
        this.pushData({
            properties: {
                controls: supportedProperties,
            },
        });
    };
    buildColumnSizing(columnWidths) {
        const growToFit = this.environment === DASHBOARDS_ENVIRONMENT;
        let columnSizing = {
            defaultWidth: "autoresizeAll",
        };
        if (growToFit) {
            columnSizing = {
                ...columnSizing,
                growToFit: true,
            };
        }
        if (columnWidths && columnWidths.length > 0) {
            columnSizing = {
                ...columnSizing,
                columnWidths,
            };
        }
        return columnSizing;
    }
    buildColorMapping(colorMapping) {
        const validColorMapping = compact(colorMapping).map((mapItem) => ({
            predicate: ColorUtils.getColorMappingPredicate(mapItem.id),
            color: mapItem.color,
        }));
        return validColorMapping?.length > 0 ? validColorMapping : undefined;
    }
    getExtendedConfig(options, insight) {
        const { config = {}, customVisualizationConfig = {} } = options;
        const properties = insightProperties(insight);
        return {
            ...(properties?.["controls"] ?? {}),
            ...config,
            ...properties,
            ...customVisualizationConfig,
        };
    }
    handleConfirmedColorMapping(data) {
        const resultingData = data;
        this.colors = data.colors;
        if (this.visualizationProperties) {
            resultingData.properties = getValidProperties(this.visualizationProperties, data.colors?.colorAssignments);
            this.visualizationProperties = resultingData.properties;
        }
        this.pushData(resultingData);
        this.renderConfigurationPanel(this.currentInsight, this.currentOptions);
    }
    handlePushData = (data) => {
        if (data.colors) {
            this.handleConfirmedColorMapping(data);
        }
        else {
            this.pushData(data);
        }
    };
    renderVisualization(options, insight, executionFactory) {
        const { locale, custom = {} } = options;
        const { drillableItems } = custom;
        const execution = this.getExecution(options, insight, executionFactory);
        let extendedConfig = this.getExtendedConfig(options, insight);
        extendedConfig = {
            ...extendedConfig,
            columnSizing: this.buildColumnSizing(extendedConfig?.columnWidths),
            colorMapping: this.buildColorMapping(extendedConfig?.colorMapping),
        };
        this.renderFun(_jsx(CoreRepeater, { enableExecutionCancelling: extendedConfig.enableExecutionCancelling ?? false, execution: execution, drillableItems: drillableItems, onDrill: this.onDrill, locale: locale, config: updateConfigWithSettings(extendedConfig, this.featureFlags), afterRender: this.afterRender, onLoadingChanged: this.onLoadingChanged, pushData: this.handlePushData, onError: this.onError, onDataView: this.onDataView, onColumnResized: this.onColumnResized, theme: undefined }), this.getElement());
    }
    renderConfigurationPanel(insight, options) {
        const configPanelElement = this.getConfigPanelElement();
        if (configPanelElement) {
            this.renderFun(_jsx(RepeaterConfigurationPanel, { colors: this.colors, locale: this.locale, properties: this.visualizationProperties, propertiesMeta: this.propertiesMeta, insight: insight, pushData: this.handlePushData, isError: this.getIsError(), isLoading: this.isLoading, featureFlags: this.featureFlags, permissions: this.permissions, configurationPanelRenderers: omit(options.custom?.configurationPanelRenderers, "InteractionsDetailRenderer") }), configPanelElement);
        }
    }
}
//# sourceMappingURL=PluggableRepeater.js.map