import { jsx as _jsx } from "react/jsx-runtime";
// (C) 2019-2026 GoodData Corporation
import { cloneDeep, compact, isEmpty, omitBy, set, tail } from "lodash-es";
import { insightHasMeasures, } from "@gooddata/sdk-model";
import { BucketNames, VisualizationTypes } from "@gooddata/sdk-ui";
import { BaseChart, ColorUtils, updateConfigWithSettings, updateForecastWithSettings, updateOutliersWithSettings, } from "@gooddata/sdk-ui-charts";
import { messages } from "../../../../locales.js";
import { BUCKETS } from "../../../constants/bucket.js";
import { DASHBOARDS_ENVIRONMENT } from "../../../constants/properties.js";
import { DEFAULT_CLUSTERING_THRESHOLD, DEFAULT_NUMBER_OF_CLUSTERS } from "../../../constants/scatter.js";
import { BASE_CHART_SUPPORTED_PROPERTIES } from "../../../constants/supportedProperties.js";
import { DEFAULT_BASE_CHART_UICONFIG, MAX_CATEGORIES_COUNT, defaultImprovedFilters, } from "../../../constants/uiConfig.js";
import { InvalidBucketsSdkError, } from "../../../interfaces/Visualization.js";
import { configureOverTimeComparison, configurePercent } from "../../../utils/bucketConfig.js";
import { filterOutDerivedMeasures, getAllAttributeItemsWithPreference, getAttributeItemsWithoutStacks, getFilteredMeasuresForStackedCharts, getMeasureItems, getStackItems, isNotDateBucketItem, sanitizeFilters, } from "../../../utils/bucketHelper.js";
import { getValidProperties } from "../../../utils/colors.js";
import { generateDimensions } from "../../../utils/dimensions.js";
import { isForecastEnabled } from "../../../utils/forecastHelper.js";
import { getChartSupportedControls, getChartSupportedControlsDashboardsEnv, getReferencePointWithSupportedProperties, getSupportedPropertiesControls, hasColorMapping, isEmptyObject, } from "../../../utils/propertiesHelper.js";
import { createSorts, validateCurrentSort } from "../../../utils/sort.js";
import { getTranslation } from "../../../utils/translations.js";
import { setBaseChartUiConfig, setBaseChartUiConfigRecommendations, } from "../../../utils/uiConfigHelpers/baseChartUiConfigHelper.js";
import { isOpenAsReportSupportedByVisualization } from "../../../utils/visualizationsHelper.js";
import { BaseChartConfigurationPanel } from "../../configurationPanels/BaseChartConfigurationPanel.js";
import { AbstractPluggableVisualization } from "../AbstractPluggableVisualization.js";
import { addIntersectionFiltersToInsight, modifyBucketsAttributesForDrillDown } from "../drillDownUtil.js";
export class PluggableBaseChart extends AbstractPluggableVisualization {
    projectId;
    type;
    defaultControlsProperties;
    customControlsProperties;
    colors;
    references;
    referencePoint;
    ignoreUndoRedo;
    axis;
    secondaryAxis;
    environment;
    renderFun;
    unmountFun;
    backendCapabilities;
    constructor(props) {
        super(props);
        this.projectId = props.projectId ?? "";
        this.environment = props.environment ?? "";
        this.type = VisualizationTypes.COLUMN;
        this.ignoreUndoRedo = false;
        this.defaultControlsProperties = {};
        this.backendCapabilities = props.backend.capabilities;
        this.setCustomControlsProperties({});
        this.renderFun = props.renderFun;
        this.unmountFun = props.unmountFun;
        this.supportedPropertiesList = this.getSupportedPropertiesList();
    }
    unmount() {
        this.unmountFun([this.getElement(), this.getConfigPanelElement()].filter(Boolean));
    }
    /**
     * Helper method to add METRIC to filter accepts when enableImprovedAdFilters feature flag is enabled.
     * The order is important to match localization strings.
     *
     * Remove this helper when feature flag is removed and use the exact same array
     * in uiConfig.ts \> defaultFilters \> accepts
     */
    addMetricToFiltersIfEnabled(config) {
        if (this.featureFlags?.enableImprovedAdFilters && config.buckets?.["filters"]) {
            config.buckets["filters"] = defaultImprovedFilters.filters;
        }
    }
    getUiConfig() {
        const config = cloneDeep(DEFAULT_BASE_CHART_UICONFIG);
        this.addMetricToFiltersIfEnabled(config);
        return config;
    }
    getExtendedReferencePoint(referencePoint) {
        const clonedReferencePoint = cloneDeep(referencePoint);
        const uiConfig = this.getUiConfig();
        let newReferencePoint = {
            ...clonedReferencePoint,
            uiConfig,
        };
        this.configureBuckets(newReferencePoint);
        newReferencePoint = configurePercent(newReferencePoint, false);
        newReferencePoint = configureOverTimeComparison(newReferencePoint);
        newReferencePoint = setBaseChartUiConfigRecommendations(newReferencePoint, this.type);
        newReferencePoint = getReferencePointWithSupportedProperties(newReferencePoint, this.supportedPropertiesList);
        newReferencePoint = setBaseChartUiConfig(newReferencePoint, this.intl, this.type);
        this.referencePoint = newReferencePoint;
        return Promise.resolve(sanitizeFilters(newReferencePoint, this.featureFlags?.enableImprovedAdFilters, clonedReferencePoint));
    }
    getInsightWithDrillDownApplied(source, drillDownContext, backendSupportsElementUris) {
        const intersection = drillDownContext.event.drillContext.intersection;
        const withFilters = addIntersectionFiltersToInsight(source, intersection, backendSupportsElementUris);
        return modifyBucketsAttributesForDrillDown(withFilters, drillDownContext.drillDefinition);
    }
    isOpenAsReportSupported() {
        return isOpenAsReportSupportedByVisualization(this.type);
    }
    setCustomControlsProperties(customControlsProperties) {
        this.customControlsProperties = customControlsProperties;
    }
    getExecution(options, insight, executionFactory) {
        const { dateFormat, executionConfig } = options;
        const supportedControls = this.getSupportedControls(insight, options);
        return executionFactory
            .forInsight(insight)
            .withDimensions(...this.getDimensions(insight))
            .withSorting(...createSorts(this.type, insight, supportedControls))
            .withDateFormat(dateFormat)
            .withExecConfig(executionConfig);
    }
    configureBuckets(extendedReferencePoint) {
        const buckets = extendedReferencePoint?.buckets ?? [];
        const categoriesCount = extendedReferencePoint?.uiConfig?.buckets?.[BucketNames.VIEW]?.itemsLimit ?? MAX_CATEGORIES_COUNT;
        set(extendedReferencePoint, BUCKETS, [
            {
                localIdentifier: BucketNames.MEASURES,
                items: getFilteredMeasuresForStackedCharts(buckets),
            },
            {
                localIdentifier: BucketNames.VIEW,
                items: getAttributeItemsWithoutStacks(buckets).slice(0, categoriesCount),
            },
            {
                localIdentifier: BucketNames.STACK,
                items: this.getStackItems(buckets),
            },
        ]);
    }
    getSupportedPropertiesList() {
        return BASE_CHART_SUPPORTED_PROPERTIES;
    }
    getStackItems(buckets) {
        const measures = getMeasureItems(buckets);
        const masterMeasures = filterOutDerivedMeasures(measures);
        const allAttributes = getAllAttributeItemsWithPreference(buckets, [
            BucketNames.LOCATION,
            BucketNames.VIEW,
            BucketNames.TREND,
            BucketNames.STACK,
            BucketNames.SEGMENT,
        ]);
        let stacks = getStackItems(buckets);
        if (masterMeasures.length <= 1 && allAttributes.length > 1) {
            // first attribute is taken, find next available non-date attribute
            const attributesWithoutFirst = tail(allAttributes);
            const nonDate = attributesWithoutFirst.filter(isNotDateBucketItem);
            stacks = nonDate.slice(0, 1);
        }
        return stacks;
    }
    checkBeforeRender(insight) {
        super.checkBeforeRender(insight);
        if (!insightHasMeasures(insight)) {
            throw new InvalidBucketsSdkError();
        }
        return true;
    }
    renderVisualization(options, insight, executionFactory) {
        const { dimensions = { height: undefined }, custom = {}, locale, theme } = options;
        const { height } = dimensions;
        // keep height undef for AD; causes indigo-visualizations to pick default 100%
        const resultingHeight = this.environment === DASHBOARDS_ENVIRONMENT ? height : undefined;
        const { drillableItems } = custom;
        const supportedControls = this.getSupportedControls(insight, options);
        const configSupportedControls = isEmpty(supportedControls) ? undefined : supportedControls;
        const fullConfig = this.buildVisualizationConfig(options, configSupportedControls);
        const execution = this.getExecution(options, insight, executionFactory);
        this.renderFun(_jsx(BaseChart, { enableExecutionCancelling: fullConfig.enableExecutionCancelling ??
                this.featureFlags.enableExecutionCancelling ??
                false, execution: execution, afterRender: this.afterRender, drillableItems: drillableItems, onDrill: this.onDrill, onError: this.onError, onExportReady: this.onExportReady, onLoadingChanged: this.onLoadingChanged, pushData: this.handlePushData, onDataView: this.onDataView, height: resultingHeight, type: this.type, locale: locale, outliersConfig: updateOutliersWithSettings(fullConfig, this.featureFlags, isForecastEnabled(this.referencePoint, insight, this.type)), forecastConfig: updateForecastWithSettings(fullConfig, this.featureFlags, isForecastEnabled(this.referencePoint, insight, this.type)), config: updateConfigWithSettings(fullConfig, this.featureFlags), LoadingComponent: undefined, ErrorComponent: undefined, theme: theme, ...enhanceBaseChartWithClusteringConfiguration(fullConfig) }), this.getElement());
    }
    initializeProperties(visualizationProperties) {
        const controls = visualizationProperties?.controls;
        const supportedProperties = getSupportedPropertiesControls(controls, this.supportedPropertiesList);
        const initialProperties = {
            supportedProperties: { controls: supportedProperties },
        };
        this.pushData({
            initialProperties,
        });
    }
    renderConfigurationPanel(insight, options) {
        const configPanelElement = this.getConfigPanelElement();
        if (configPanelElement) {
            const panelConfig = {
                supportsAttributeHierarchies: this.backendCapabilities.supportsAttributeHierarchies,
                supportsChartFill: options.supportsChartFill,
            };
            this.renderFun(_jsx(BaseChartConfigurationPanel, { 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, permissions: this.permissions, axis: this.axis, panelConfig: panelConfig, configurationPanelRenderers: options.custom?.configurationPanelRenderers }), configPanelElement);
        }
    }
    getDimensions(insight) {
        return generateDimensions(insight, this.type);
    }
    handleConfirmedColorMapping(data) {
        const resultingData = data;
        this.colors = data.colors;
        if (isEmptyObject(this.references)) {
            resultingData.references = {};
        }
        else if (this.references) {
            resultingData.references = this.references;
        }
        if (this.visualizationProperties) {
            resultingData.properties = getValidProperties(this.visualizationProperties, data.colors.colorAssignments);
            this.visualizationProperties = resultingData.properties;
        }
        this.renderConfigurationPanel(this.currentInsight, this.currentOptions);
        const openAsReportConfig = this.getOpenAsReportConfig(resultingData.properties);
        if (this.ignoreUndoRedo) {
            this.ignoreUndoRedo = false;
            this.pushData(resultingData);
        }
        else {
            this.pushData({
                openAsReport: openAsReportConfig,
                ignoreUndoRedo: true,
                ...resultingData,
            });
        }
    }
    handlePushData = (data) => {
        if (data.colors) {
            this.handleConfirmedColorMapping(data);
        }
        else {
            const updatedData = enhancePropertiesMetaWithPartialClusteringInfo(data, this.type);
            this.pushData({
                ...updatedData,
                references: this.references,
            });
        }
    };
    buildVisualizationConfig(options, supportedControls) {
        const { config = {}, customVisualizationConfig = {}, a11yTitle, a11yDescription } = options;
        const colorMapping = supportedControls?.["colorMapping"];
        const validColorMapping = compact(colorMapping).map((mapItem) => ({
            predicate: ColorUtils.getColorMappingPredicate(mapItem.id),
            color: mapItem.color,
        }));
        return {
            separators: config.separators,
            colorPalette: config.colorPalette,
            forceDisableDrillOnAxes: config.forceDisableDrillOnAxes,
            enableExecutionCancelling: config.enableExecutionCancelling,
            enableCompactSize: true,
            a11yTitle,
            a11yDescription,
            ...supportedControls,
            colorMapping: validColorMapping?.length > 0 ? validColorMapping : null,
            supportsChartFill: options.supportsChartFill,
            ...customVisualizationConfig,
        };
    }
    getOpenAsReportConfig(properties) {
        const hasMapping = hasColorMapping(properties);
        const isSupported = this.isOpenAsReportSupported();
        const warningMessage = hasMapping
            ? getTranslation(messages["exportUnsupportedColors"].id, this.intl)
            : "";
        return {
            supported: isSupported && !hasMapping,
            warningMessage,
        };
    }
    getSupportedControls(insight, options) {
        const defaultControls = getSupportedPropertiesControls(this.defaultControlsProperties, this.supportedPropertiesList);
        const customControls = getSupportedPropertiesControls(this.customControlsProperties, this.supportedPropertiesList);
        const supportedControls = this.environment === DASHBOARDS_ENVIRONMENT
            ? getChartSupportedControlsDashboardsEnv(this.visualizationProperties?.controls, options)
            : getChartSupportedControls(this.visualizationProperties?.controls, insight);
        return {
            ...defaultControls,
            ...supportedControls,
            ...customControls,
        };
    }
    reuseCurrentSort(previousAvailableSorts, properties, availableSorts, defaultSort) {
        const previousSort = properties?.sortItems;
        return validateCurrentSort(previousAvailableSorts, previousSort, availableSorts, defaultSort);
    }
}
function enhancePropertiesMetaWithPartialClusteringInfo(data, type) {
    let dataPropertiesMeta = { propertiesMeta: data.propertiesMeta };
    if (data.dataView && type === "scatter") {
        const dataView = data.dataView;
        const numberOfDataPoints = dataView.count[0];
        const numberOfClusters = dataView.clusteringConfig?.numberOfClusters;
        const showingPartialClusters = !!numberOfClusters && numberOfDataPoints < numberOfClusters;
        dataPropertiesMeta = {
            propertiesMeta: {
                ...dataPropertiesMeta.propertiesMeta,
                showingPartialClusters,
            },
        };
    }
    return {
        ...data,
        ...omitBy(dataPropertiesMeta, isEmpty),
    };
}
function enhanceBaseChartWithClusteringConfiguration(fullConfig) {
    const threshold = fullConfig?.clustering?.threshold
        ? {
            threshold: typeof fullConfig?.clustering?.threshold === "string"
                ? parseFloat(fullConfig.clustering.threshold)
                : (fullConfig?.clustering?.threshold ?? DEFAULT_CLUSTERING_THRESHOLD),
        }
        : {};
    return !isEmpty(fullConfig.clustering) && fullConfig.clustering.enabled
        ? {
            clusteringConfig: {
                ...(fullConfig.clustering ?? {}),
                numberOfClusters: typeof fullConfig?.clustering?.numberOfClusters === "string"
                    ? parseInt(fullConfig.clustering.numberOfClusters, 10)
                    : (fullConfig?.clustering?.numberOfClusters ?? DEFAULT_NUMBER_OF_CLUSTERS),
                ...threshold,
            },
        }
        : {};
}
//# sourceMappingURL=PluggableBaseChart.js.map