import { jsx as _jsx } from "react/jsx-runtime";
// (C) 2025-2026 GoodData Corporation
import { cloneDeep, set } from "lodash-es";
import { bucketAttribute, bucketItems, insightBucket, insightBuckets, insightFilters, insightHasDataDefined, insightLayers, insightTitle, newAttribute, } from "@gooddata/sdk-model";
import { BucketNames, VisualizationTypes } from "@gooddata/sdk-ui";
import { GeoChartNextInternal, buildLayerExecution, createAreaLayer, insightLayersToGeoLayers, isGeoLayerPushpin, } from "@gooddata/sdk-ui-geo/next";
import { createAreaConfiguredBuckets, createAreaSortForSegment, getAreaItems, getAreaTooltipText, getColorMeasures, getSegmentItems, hasAreaMinimumData, sanitizeAreaMeasures, } from "./geoAreaBucketHelper.js";
import { buildAreaVisualizationConfig } from "./geoAreaConfigBuilder.js";
import { BUCKETS } from "../../../constants/bucket.js";
import { GEOAREA_SUPPORTED_PROPERTIES } from "../../../constants/supportedProperties.js";
import { GEO_AREA_CHART_UICONFIG } from "../../../constants/uiConfig.js";
import { EmptyAfmSdkError, } from "../../../interfaces/Visualization.js";
import { configurePercent } from "../../../utils/bucketConfig.js";
import { limitNumberOfMeasuresInBuckets } from "../../../utils/bucketHelper.js";
import { routeLocalIdRefFiltersToLayers } from "../../../utils/filters/routeLocalIdRefFiltersToLayers.js";
import { removeSort } from "../../../utils/sort.js";
import { setGeoAreaUiConfig } from "../../../utils/uiConfigHelpers/geoAreaChartUiConfigHelper.js";
import { GeoAreaConfigurationPanel } from "../../configurationPanels/GeoAreaConfigurationPanel.js";
import { PluggableBaseChart } from "../baseChart/PluggableBaseChart.js";
import { createAttributeRef } from "../geoChartNext/geoAttributeHelper.js";
/**
 * Geo area charts support max 1 measure for color
 */
const NUMBER_MEASURES_IN_BUCKETS_LIMIT = 1;
/**
 * PluggableGeoAreaChart
 *
 * Next-generation geo area chart implementation
 *
 * @alpha
 */
export class PluggableGeoAreaChart extends PluggableBaseChart {
    backend;
    workspace;
    constructor(props) {
        super(props);
        this.type = VisualizationTypes.CHOROPLETH;
        this.backend = props.backend;
        this.workspace = props.projectId;
        this.initializeProperties(props.visualizationProperties);
    }
    /**
     * Extends reference point with geo area-specific configuration.
     */
    getExtendedReferencePoint(referencePoint) {
        // IMPORTANT:
        // GeoChartNext is multi-layer, but AD's reference point contains a single buckets model.
        // The generic sanitizeFilters() (in PluggableBaseChart) does not know about additional layers and can
        // incorrectly drop MVFs that are meant for non-root layers (e.g., pushpin layer MVFs).
        // We keep the original filter bucket intact here and rely on per-layer execution sanitization instead.
        const originalFilters = cloneDeep(referencePoint.filters);
        return super
            .getExtendedReferencePoint(referencePoint)
            .then((extendedReferencePoint) => {
            let newReferencePoint = setGeoAreaUiConfig(extendedReferencePoint, this.intl);
            newReferencePoint = configurePercent(newReferencePoint, true);
            newReferencePoint = removeSort(newReferencePoint);
            const tooltipText = this.visualizationProperties?.controls?.["tooltipText"];
            const withTooltip = this.applyTooltipProperty(newReferencePoint, tooltipText);
            return { ...withTooltip, filters: originalFilters };
        });
    }
    getUiConfig() {
        return cloneDeep(GEO_AREA_CHART_UICONFIG);
    }
    getSupportedPropertiesList() {
        return GEOAREA_SUPPORTED_PROPERTIES;
    }
    /**
     * Configures buckets for geo area chart.
     */
    configureBuckets(extendedReferencePoint) {
        const sanitized = sanitizeAreaMeasures(extendedReferencePoint);
        const buckets = limitNumberOfMeasuresInBuckets(sanitized.buckets, NUMBER_MEASURES_IN_BUCKETS_LIMIT);
        const uiConfig = this.getUiConfig();
        const areaItems = getAreaItems(buckets, uiConfig);
        const tooltipText = this.resolveTooltipText(areaItems[0]);
        const segmentItems = getSegmentItems(buckets);
        const colorMeasures = getColorMeasures(buckets);
        const configuredBuckets = createAreaConfiguredBuckets(buckets, areaItems, segmentItems, colorMeasures, uiConfig);
        set(sanitized, BUCKETS, configuredBuckets);
        this.updateTooltipVisualizationProperties(tooltipText);
        return this.applyTooltipProperty(sanitized, tooltipText);
    }
    /**
     * Validates insight has data defined before rendering.
     */
    checkBeforeRender(insight) {
        if (!insightHasDataDefined(insight)) {
            throw new EmptyAfmSdkError();
        }
        const buckets = insightBuckets(insight);
        if (!hasAreaMinimumData(buckets)) {
            throw new EmptyAfmSdkError();
        }
        return true;
    }
    /**
     * Creates execution for geo area chart.
     *
     * @remarks
     * This method is called by the base visualization infrastructure for exports
     * and other external consumers. The internal rendering uses `buildLayerExecution()`
     * which works with the layer-based architecture.
     */
    getExecution(options, insight, executionFactory) {
        const { primaryLayer, config, filters } = this.buildPrimaryLayerContext(options, insight);
        const { globalFilters, routedByLayerId } = routeLocalIdRefFiltersToLayers(filters, [
            { id: primaryLayer.id, buckets: insightBuckets(insight) },
            ...insightLayers(insight).map((l) => ({ id: l.id, buckets: l.buckets })),
        ]);
        const effectiveFilters = [...globalFilters, ...(routedByLayerId.get(primaryLayer.id) ?? [])];
        return buildLayerExecution(primaryLayer, {
            backend: this.backend,
            workspace: this.workspace,
            config,
            execConfig: options.executionConfig,
            globalFilters: effectiveFilters,
            executionFactory,
        });
    }
    getExecutions(options, insight, executionFactory) {
        const { primaryLayer, config, filters } = this.buildPrimaryLayerContext(options, insight);
        const { globalFilters, routedByLayerId } = routeLocalIdRefFiltersToLayers(filters, [
            { id: primaryLayer.id, buckets: insightBuckets(insight) },
            ...insightLayers(insight).map((l) => ({ id: l.id, buckets: l.buckets })),
        ]);
        const insightLayerDefs = insightLayers(insight);
        const additionalLayers = insightLayersToGeoLayers(insightLayerDefs);
        const resolvedAdditionalLayers = additionalLayers.filter((layer) => !this.shouldSkipLayer(layer));
        return this.buildAdditionalLayerExecutions(resolvedAdditionalLayers, options, config, globalFilters, routedByLayerId, executionFactory);
    }
    renderConfigurationPanel(insight, options) {
        const configPanelElement = this.getConfigPanelElement();
        if (configPanelElement) {
            this.renderFun(_jsx(GeoAreaConfigurationPanel, { locale: this.locale, pushData: this.pushData, properties: this.visualizationProperties, references: this.references, propertiesMeta: this.propertiesMeta, insight: insight, colors: this.colors, type: this.type, isError: this.getIsError(), isLoading: this.isLoading, featureFlags: this.featureFlags, configurationPanelRenderers: options.custom?.configurationPanelRenderers }), configPanelElement);
        }
    }
    /**
     * Builds geo area-specific visualization configuration.
     */
    buildVisualizationConfig(options, supportedControls) {
        const { colorMapping } = super.buildVisualizationConfig(options, supportedControls);
        return buildAreaVisualizationConfig({
            options,
            supportedControls,
            colorMapping,
            environment: this.environment,
        });
    }
    renderVisualization(options, insight, executionFactory) {
        const { custom = {}, locale, theme } = options;
        const { drillableItems } = custom;
        const { config: configWithTooltip } = this.buildPrimaryLayerContext(options, insight);
        const primaryExecution = this.getExecution(options, insight, executionFactory);
        const additionalLayerExecutions = this.getExecutions(options, insight, executionFactory) ?? [];
        const geoChartProps = {
            backend: this.backend,
            workspace: this.workspace,
            type: "area",
            execution: primaryExecution,
            executions: additionalLayerExecutions,
            execConfig: options.executionConfig,
            drillableItems,
            config: configWithTooltip,
            locale,
            theme,
            pushData: this.handlePushData,
            afterRender: this.afterRender,
            onError: this.onError,
            onExportReady: this.onExportReady,
            onLoadingChanged: this.onLoadingChanged,
            onDrill: this.onDrill,
        };
        this.renderFun(_jsx(GeoChartNextInternal, { ...geoChartProps }), this.getElement());
    }
    buildPrimaryLayerContext(options, insight) {
        const supportedControls = this.visualizationProperties.controls || {};
        const fullConfig = this.buildVisualizationConfig(options, supportedControls);
        const filters = insightFilters(insight);
        const sortBy = createAreaSortForSegment(insight);
        const areaBucket = insightBucket(insight, BucketNames.AREA);
        const area = areaBucket ? bucketAttribute(areaBucket) : undefined;
        const colorBucket = insightBucket(insight, BucketNames.COLOR);
        const color = colorBucket ? bucketItems(colorBucket)[0] : undefined;
        const segmentBucket = insightBucket(insight, BucketNames.SEGMENT);
        const segmentBy = segmentBucket ? bucketAttribute(segmentBucket) : undefined;
        const tooltipTextId = supportedControls?.["tooltipText"];
        const tooltipTextAttribute = this.createTooltipTextAttribute(area, tooltipTextId);
        const configWithTooltip = tooltipTextAttribute
            ? { ...fullConfig, tooltipText: tooltipTextAttribute }
            : fullConfig;
        // Set primary layer name to the insight title so legend/title logic is consistent for all layers.
        const title = insightTitle(insight);
        const primaryLayer = createAreaLayer({
            ...(title ? { name: title } : {}),
            area: area,
            ...(color ? { color } : {}),
            ...(segmentBy ? { segmentBy } : {}),
            sortBy,
        });
        return {
            primaryLayer,
            config: configWithTooltip,
            filters,
        };
    }
    buildAdditionalLayerExecutions(layers, options, config, globalFilters, routedByLayerId, executionFactory) {
        if (!layers.length) {
            return [];
        }
        return layers.map((layer) => {
            const effectiveFilters = [...globalFilters, ...(routedByLayerId.get(layer.id) ?? [])];
            return buildLayerExecution(layer, {
                backend: this.backend,
                workspace: this.workspace,
                config,
                execConfig: options.executionConfig,
                globalFilters: effectiveFilters,
                executionFactory,
            });
        });
    }
    shouldSkipLayer(layer) {
        if (!isGeoLayerPushpin(layer)) {
            return false;
        }
        // Skip layers when latitude or longitude is missing
        return !layer.latitude || !layer.longitude;
    }
    createTooltipTextAttribute(area, tooltipTextId) {
        if (!area || !tooltipTextId) {
            return undefined;
        }
        const tooltipRef = createAttributeRef(area, tooltipTextId);
        return newAttribute(tooltipRef, (attribute) => attribute.localId("tooltipText_df"));
    }
    resolveTooltipText(areaItem) {
        if (!areaItem) {
            return undefined;
        }
        return getAreaTooltipText(areaItem);
    }
    updateTooltipVisualizationProperties(tooltipText) {
        if (!tooltipText) {
            return;
        }
        const currentProperties = this.visualizationProperties ?? {};
        const currentControls = currentProperties.controls ?? {};
        this.visualizationProperties = {
            ...currentProperties,
            controls: {
                ...currentControls,
                tooltipText,
            },
        };
    }
    applyTooltipProperty(referencePoint, tooltipText) {
        if (!tooltipText) {
            return referencePoint;
        }
        const updated = cloneDeep(referencePoint);
        const properties = updated.properties ?? {};
        const controls = properties.controls ?? {};
        set(updated, "properties.controls", {
            ...controls,
            tooltipText,
        });
        return updated;
    }
}
//# sourceMappingURL=PluggableGeoAreaChart.js.map