'use client';
import * as React from 'react';
import { useGroupedVerticalBarChartStyles_unstable } from './useGroupedVerticalBarChartStyles.styles';
import { pointer as d3Pointer } from 'd3-selection';
import { max as d3Max, min as d3Min } from 'd3-array';
import { scaleBand as d3ScaleBand } from 'd3-scale';
import { useId } from '@fluentui/react-utilities';
import { ChartTypes, getAccessibleDataObject, XAxisTypes, getTypeOfAxis, formatScientificLimitWidth, getScalePadding, getBarWidth, isScalePaddingDefined, createNumericYAxis, domainRangeOfXStringAxis, createStringYAxis, getNextColor, areArraysEqual, calculateLongestLabelWidth, useRtl, calcRequiredWidth, calcTotalWidth, calcBandwidth, calcTotalBandUnits, sortAxisCategories } from '../../utilities/index';
import { CartesianChart, Legends, getColorFromToken } from '../../index';
import { tokens } from '@fluentui/react-theme';
import { useImageExport } from '../../utilities/hooks';
import { isInvalidValue } from '@fluentui/chart-utilities';
const MIN_DOMAIN_MARGIN = 8;
const X1_INNER_PADDING = 0.1;
const VERTICAL_BAR_GAP = 1;
const MIN_BAR_HEIGHT = 1;
export const GroupedVerticalBarChart = /*#__PURE__*/ React.forwardRef((_props, forwardedRef)=>{
    var _props_legendProps, _props_legendProps1, _barData_, _lineData__data_, _lineData_;
    const props = {
        xAxisCategoryOrder: 'default',
        maxBarWidth: 24,
        ..._props
    };
    const _emptyChartId = useId('_GVBC_empty');
    const _useRtl = useRtl();
    let _domainMargin = MIN_DOMAIN_MARGIN;
    let _xAxisLabels = [];
    let _datasetForBars = [];
    let _margins = {
        top: 0,
        right: 0,
        bottom: 0,
        left: 0
    };
    let _groupedVerticalBarGraph = [];
    let _yMax = 0;
    let _calloutAnchorPoint = null;
    let _barWidth = 0;
    let _groupWidth = 0;
    let _xAxisInnerPadding = 0;
    let _xAxisOuterPadding = 0;
    let _barLegends = [];
    let _lineLegends = [];
    let _legendColorMap = {};
    const { cartesianChartRef, legendsRef: _legendsRef } = useImageExport(props.componentRef, props.hideLegend);
    const Y_ORIGIN = 0;
    const _rectRef = React.useRef(null);
    const _uniqDotId = useId('gvbc_dot_');
    const [color, setColor] = React.useState('');
    const [dataForHoverCard, setDataForHoverCard] = React.useState(0);
    const [selectedLegends, setSelectedLegends] = React.useState(((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends) || []);
    const [xCalloutValue, setXCalloutValue] = React.useState('');
    const [yCalloutValue, setYCalloutValue] = React.useState('');
    const [yValueHover, setYValueHover] = React.useState([]);
    const [hoverXValue, setHoverXValue] = React.useState('');
    const [calloutLegend, setCalloutLegend] = React.useState('');
    const [activeLegend, setActiveLegend] = React.useState('');
    const [callOutAccessibilityData, setCallOutAccessibilityData] = React.useState(undefined);
    const [popoverTarget, setPopoverTarget] = React.useState(null);
    const [isPopoverOpen, setPopoverOpen] = React.useState(false);
    const [activeLinePoint, setActiveLinePoint] = React.useState('');
    const classes = useGroupedVerticalBarChartStyles_unstable(props);
    React.useEffect(()=>{
        var _props_legendProps;
        if (!areArraysEqual((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends, selectedLegends)) {
            var _props_legendProps1;
            setSelectedLegends(((_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.selectedLegends) || []);
        }
    }, [
        (_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.selectedLegends
    ]);
    const _adjustProps = ()=>{
        _barWidth = getBarWidth(props.barWidth, props.maxBarWidth);
        // x0_inner_padding = space_between_groups / (space_between_groups + group_width)
        // space_between_groups = 2 * bar_width
        // group_width = _barLegends.length * bar_width + (_barLegends.length - 1) * space_between_bars
        _xAxisInnerPadding = getScalePadding(props.xAxisInnerPadding, undefined, 2 / (2 + calcTotalBandUnits(_barLegends.length, X1_INNER_PADDING)));
        _xAxisOuterPadding = getScalePadding(props.xAxisOuterPadding);
    };
    const _createDataset = (barData, lineData)=>{
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const datasetForBars = [];
        const linePointsByX = {};
        const visitedX = new Set();
        lineData.forEach((series)=>{
            series.data.forEach((point)=>{
                if (!linePointsByX[point.x]) {
                    linePointsByX[point.x] = [];
                }
                linePointsByX[point.x].push({
                    ...point,
                    legend: series.legend,
                    color: series.color,
                    data: point.y,
                    useSecondaryYScale: series.useSecondaryYScale
                });
            });
        });
        barData.forEach((point, index)=>{
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const singleDatasetPointForBars = {};
            const legendToBarPoint = {};
            point.series.forEach((seriesPoint)=>{
                if (!singleDatasetPointForBars[seriesPoint.legend]) {
                    singleDatasetPointForBars[seriesPoint.legend] = [
                        {
                            ...seriesPoint
                        }
                    ];
                    legendToBarPoint[seriesPoint.legend] = {
                        ...seriesPoint
                    };
                } else {
                    singleDatasetPointForBars[seriesPoint.legend].push({
                        ...seriesPoint
                    });
                    legendToBarPoint[seriesPoint.legend].data += seriesPoint.data;
                }
            });
            singleDatasetPointForBars.xAxisPoint = point.name;
            singleDatasetPointForBars.indexNum = index;
            var _linePointsByX_point_name;
            singleDatasetPointForBars.groupSeries = [
                ...Object.values(legendToBarPoint),
                ...(_linePointsByX_point_name = linePointsByX[point.name]) !== null && _linePointsByX_point_name !== void 0 ? _linePointsByX_point_name : []
            ];
            singleDatasetPointForBars.stackCallOutAccessibilityData = point.stackCallOutAccessibilityData;
            datasetForBars.push(singleDatasetPointForBars);
            visitedX.add(point.name);
        });
        Object.keys(linePointsByX).forEach((xPoint)=>{
            if (!visitedX.has(xPoint)) {
                datasetForBars.push({
                    xAxisPoint: xPoint,
                    groupSeries: linePointsByX[xPoint]
                });
            }
        });
        return datasetForBars;
    };
    const _createDataSetOfGVBC = (barData, lineData)=>{
        const barLegends = new Set();
        barData.forEach((point)=>{
            point.series.forEach((seriesPoint)=>{
                barLegends.add(seriesPoint.legend);
            });
        });
        const lineLegends = new Set(lineData.map((series)=>series.legend));
        const xAxisLabels = _getOrderedXAxisLabels(barData, lineData);
        const datasetForBars = _createDataset(barData, lineData);
        return {
            barLegends: Array.from(barLegends),
            lineLegends: Array.from(lineLegends),
            xAxisLabels,
            datasetForBars
        };
    };
    const onLegendSelectionChange = (selectedLegends, event, currentLegend)=>{
        var _props_legendProps, _props_legendProps1;
        if ((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.canSelectMultipleLegends) {
            setSelectedLegends(selectedLegends);
        } else {
            setSelectedLegends(selectedLegends.slice(-1));
        }
        if ((_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.onChange) {
            props.legendProps.onChange(selectedLegends, event, currentLegend);
        }
    };
    const _getLegendData = ()=>{
        const actions = [];
        const addLegendButton = (legendTitle, isLineLegendInBarChart)=>{
            const legend = {
                title: legendTitle,
                color: _legendColorMap[legendTitle][0],
                isLineLegendInBarChart,
                hoverAction: ()=>{
                    _handleChartMouseLeave();
                    _onLegendHover(legendTitle);
                },
                onMouseOutAction: ()=>{
                    _onLegendLeave();
                }
            };
            actions.push(legend);
        };
        _lineLegends.forEach((legendTitle)=>addLegendButton(legendTitle, true));
        _barLegends.forEach((legendTitle)=>addLegendButton(legendTitle));
        return /*#__PURE__*/ React.createElement(Legends, {
            legends: actions,
            enabledWrapLines: props.enabledLegendsWrapLines,
            overflowText: props.legendsOverflowText,
            ...props.legendProps,
            onChange: onLegendSelectionChange,
            legendRef: _legendsRef
        });
    };
    const _processDataV2 = (dataV2)=>{
        const barPointsByX = {};
        const lineData = [];
        dataV2.forEach((series)=>{
            if (series.type === 'bar') {
                series.data.forEach((point)=>{
                    if (!barPointsByX[point.x]) {
                        barPointsByX[point.x] = {
                            name: point.x,
                            series: []
                        };
                    }
                    var _series_key, _point_color;
                    barPointsByX[point.x].series.push({
                        key: (_series_key = series.key) !== null && _series_key !== void 0 ? _series_key : series.legend,
                        data: point.y,
                        color: (_point_color = point.color) !== null && _point_color !== void 0 ? _point_color : series.color,
                        // gradient: series.gradient,
                        legend: series.legend,
                        xAxisCalloutData: point.xAxisCalloutData,
                        yAxisCalloutData: point.yAxisCalloutData,
                        onClick: point.onClick,
                        useSecondaryYScale: series.useSecondaryYScale
                    });
                });
            } else if (series.type === 'line') {
                lineData.push(series);
            }
        });
        return {
            barData: Object.values(barPointsByX),
            lineData
        };
    };
    const _prepareChartData = ()=>{
        let barData = props.data;
        let lineData;
        if (Array.isArray(props.dataV2) && props.dataV2.length > 0) {
            ({ barData, lineData } = _processDataV2(props.dataV2));
        }
        _legendColorMap = {};
        let colorIndex = 0;
        var _barData_map, _lineData_map;
        return {
            barData: (_barData_map = barData === null || barData === void 0 ? void 0 : barData.map((point)=>{
                var _point_series;
                var _point_series_map;
                return {
                    ...point,
                    series: (_point_series_map = (_point_series = point.series) === null || _point_series === void 0 ? void 0 : _point_series.map((seriesPoint)=>{
                        // TODO: Add support for gradient colors
                        const startColor = seriesPoint.color ? seriesPoint.color : getNextColor(colorIndex, 0);
                        const endColor = startColor;
                        if (!_legendColorMap[seriesPoint.legend]) {
                            _legendColorMap[seriesPoint.legend] = [
                                startColor,
                                endColor
                            ];
                        }
                        colorIndex += 1;
                        var _seriesPoint_color;
                        return {
                            ...seriesPoint,
                            color: (_seriesPoint_color = seriesPoint.color) !== null && _seriesPoint_color !== void 0 ? _seriesPoint_color : _legendColorMap[seriesPoint.legend][0]
                        };
                    })) !== null && _point_series_map !== void 0 ? _point_series_map : []
                };
            })) !== null && _barData_map !== void 0 ? _barData_map : [],
            lineData: (_lineData_map = lineData === null || lineData === void 0 ? void 0 : lineData.map((series)=>{
                let lineColor;
                if (typeof series.color === 'undefined') {
                    lineColor = getNextColor(colorIndex, 0);
                } else {
                    lineColor = getColorFromToken(series.color);
                }
                if (!_legendColorMap[series.legend]) {
                    _legendColorMap[series.legend] = [
                        lineColor,
                        lineColor
                    ];
                }
                colorIndex += 1;
                return {
                    ...series,
                    color: _legendColorMap[series.legend][0]
                };
            })) !== null && _lineData_map !== void 0 ? _lineData_map : []
        };
    };
    const _getOrderedXAxisLabels = (barData, lineData)=>{
        if (_xAxisType !== XAxisTypes.StringAxis) {
            return [];
        }
        return sortAxisCategories(_mapCategoryToValues(barData, lineData), props.xAxisCategoryOrder);
    };
    const _mapCategoryToValues = (barData, lineData)=>{
        const categoryToValues = {};
        barData.forEach((point)=>{
            if (!categoryToValues[point.name]) {
                categoryToValues[point.name] = [];
            }
            point.series.forEach((seriesPoint)=>{
                categoryToValues[point.name].push(seriesPoint.data);
            });
        });
        lineData.forEach((series)=>{
            series.data.forEach((point)=>{
                if (!categoryToValues[point.x]) {
                    categoryToValues[point.x] = [];
                }
                categoryToValues[point.x].push(point.y);
            });
        });
        return categoryToValues;
    };
    const { barData, lineData } = _prepareChartData();
    var _barData__name;
    const firstXValue = (_barData__name = (_barData_ = barData[0]) === null || _barData_ === void 0 ? void 0 : _barData_.name) !== null && _barData__name !== void 0 ? _barData__name : (_lineData_ = lineData[0]) === null || _lineData_ === void 0 ? void 0 : (_lineData__data_ = _lineData_.data[0]) === null || _lineData__data_ === void 0 ? void 0 : _lineData__data_.x;
    const _xAxisType = isInvalidValue(firstXValue) ? XAxisTypes.StringAxis : getTypeOfAxis(firstXValue, true);
    const { barLegends, lineLegends, xAxisLabels, datasetForBars } = _createDataSetOfGVBC(barData, lineData);
    _barLegends = barLegends;
    _lineLegends = lineLegends;
    _xAxisLabels = xAxisLabels;
    _datasetForBars = datasetForBars;
    const legendBars = _getLegendData();
    _adjustProps();
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Add commentMore actions
    function _getMinMaxOfYAxis(datasetForBars, yAxisType, useSecondaryYScale) {
        const values = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        datasetForBars.forEach((data)=>{
            data.groupSeries.forEach((point)=>{
                if (!useSecondaryYScale === !point.useSecondaryYScale) {
                    values.push(point.data);
                }
            });
        });
        return {
            startValue: d3Min(values),
            endValue: d3Max(values)
        };
    }
    function _getDomainNRangeValues(points, margins, width, chartType, isRTL, xAxisType, barWidth, tickValues) {
        let domainNRangeValue;
        if (xAxisType === XAxisTypes.NumericAxis || xAxisType === XAxisTypes.DateAxis) {
            domainNRangeValue = {
                dStartValue: 0,
                dEndValue: 0,
                rStartValue: 0,
                rEndValue: 0
            };
        } else {
            domainNRangeValue = domainRangeOfXStringAxis(margins, width, isRTL);
        }
        return domainNRangeValue;
    }
    // The maxOfYVal prop is only required for the primary y-axis, so yMax should be calculated
    // using only the data points associated with the primary y-axis.
    const yMax = _getMinMaxOfYAxis(_datasetForBars).endValue;
    _yMax = Math.max(yMax, props.yMaxValue || 0);
    const calloutProps = {
        positioning: {
            target: popoverTarget
        },
        isPopoverOpen,
        color,
        legend: calloutLegend,
        XValue: xCalloutValue,
        YValue: yCalloutValue ? yCalloutValue : dataForHoverCard,
        YValueHover: yValueHover,
        hoverXValue,
        culture: props.culture,
        isCartesian: true,
        isCalloutForStack: props.isCalloutForStack,
        ...props.calloutProps,
        ...getAccessibleDataObject(callOutAccessibilityData, 'text', false)
    };
    const tickParams = {
        tickValues: props.tickValues,
        tickFormat: props.tickFormat
    };
    const _getGraphData = (xScale, yScalePrimary, containerHeight, containerWidth, xElement, yAxisElement, yScaleSecondary)=>{
        const xScale0 = _createX0Scale(containerWidth);
        // Setting the bar width here is safe because there are no dependencies earlier in the code
        // that rely on the width of bars in vertical bar charts with string x-axis.
        _barWidth = getBarWidth(props.barWidth, props.maxBarWidth, calcBandwidth(xScale0.bandwidth(), _barLegends.length, X1_INNER_PADDING));
        _groupWidth = calcRequiredWidth(_barWidth, _barLegends.length, X1_INNER_PADDING);
        const xScale1 = _createX1Scale();
        const allGroupsBars = [];
        _datasetForBars.forEach((singleSet)=>{
            allGroupsBars.push(_buildGraph(singleSet, xScale0, xScale1, yScalePrimary, yScaleSecondary, containerHeight, xElement));
        });
        _groupedVerticalBarGraph = allGroupsBars;
    };
    const _getMargins = (margins)=>{
        _margins = margins;
    };
    const onBarHover = (pointData, // eslint-disable-next-line @typescript-eslint/no-explicit-any
    groupData, mouseEvent)=>{
        mouseEvent.persist();
        if (_calloutAnchorPoint !== pointData) {
            _calloutAnchorPoint = pointData;
            _showCallout(mouseEvent.currentTarget, pointData, groupData);
        }
    };
    const _onBarLeave = ()=>{
    /**/ };
    const _handleChartMouseLeave = ()=>{
        _calloutAnchorPoint = null;
        setPopoverOpen(false);
    };
    const onBarFocus = (focusEvent, pointData, // eslint-disable-next-line @typescript-eslint/no-explicit-any
    groupData)=>{
        _showCallout(focusEvent.currentTarget, pointData, groupData);
    };
    const _buildGraph = (// eslint-disable-next-line @typescript-eslint/no-explicit-any
    singleSet, // eslint-disable-next-line @typescript-eslint/no-explicit-any
    xScale0, // eslint-disable-next-line @typescript-eslint/no-explicit-any
    xScale1, yScalePrimary, yScaleSecondary, containerHeight, xElement)=>{
        const singleGroup = [];
        const barLabelsForGroup = [];
        // Get the actual legends present at this x-axis point
        const presentLegends = _barLegends.filter((key)=>key in singleSet);
        const effectiveGroupWidth = calcRequiredWidth(_barWidth, presentLegends.length, X1_INNER_PADDING);
        // For stacked bars, center the single bar group in the available space
        // Instead of using the global legend position, use the local position within present legends
        const localScale = d3ScaleBand().domain(presentLegends).range(_useRtl ? [
            effectiveGroupWidth,
            0
        ] : [
            0,
            effectiveGroupWidth
        ]).paddingInner(X1_INNER_PADDING);
        _barLegends.forEach((legendTitle, legendIndex)=>{
            const barPoints = singleSet[legendTitle];
            if (barPoints) {
                const yBarScale = barPoints[0].useSecondaryYScale && yScaleSecondary ? yScaleSecondary : yScalePrimary;
                var _localScale;
                const xPoint = ((_localScale = localScale(legendTitle)) !== null && _localScale !== void 0 ? _localScale : 0) + (localScale.bandwidth() - _barWidth) / 2;
                const isLegendActive = _legendHighlighted(legendTitle) || _noLegendHighlighted();
                const barOpacity = isLegendActive ? '' : '0.1';
                let barTotalValue = 0;
                const yBaseline = yBarScale(Y_ORIGIN);
                let yPositiveStart = yBaseline;
                let yNegativeStart = yBaseline;
                let yPoint = Y_ORIGIN;
                barPoints.forEach((pointData, pointIndex)=>{
                    if (!pointData.data) {
                        // Not rendering data with 0.
                        return;
                    }
                    const barGap = VERTICAL_BAR_GAP / 2 * (pointIndex > 0 ? 2 : 0);
                    const height = Math.max(yBarScale(Y_ORIGIN) - yBarScale(Math.abs(pointData.data)), MIN_BAR_HEIGHT);
                    const pointColor = pointData.color; // Use the color of the current point
                    if (pointData.data >= Y_ORIGIN) {
                        yPositiveStart -= height + barGap;
                        yPoint = yPositiveStart;
                    } else {
                        yPoint = yNegativeStart + barGap;
                        yNegativeStart = yPoint + height;
                    }
                    singleGroup.push(/*#__PURE__*/ React.createElement("rect", {
                        key: `${singleSet.indexNum}-${legendIndex}-${pointIndex}`,
                        className: classes.opacityChangeOnHover,
                        height: height,
                        width: _barWidth,
                        x: xPoint,
                        y: yPoint,
                        opacity: barOpacity,
                        fill: pointColor,
                        rx: props.roundCorners ? 3 : 0,
                        onMouseOver: (event)=>onBarHover(pointData, singleSet, event),
                        onMouseMove: (event)=>onBarHover(pointData, singleSet, event),
                        onMouseOut: _onBarLeave,
                        onFocus: (event)=>onBarFocus(event, pointData, singleSet),
                        onBlur: _onBarLeave,
                        onClick: pointData.onClick,
                        "aria-label": getAriaLabel(pointData, singleSet.xAxisPoint),
                        tabIndex: _legendHighlighted(pointData.legend) || _noLegendHighlighted() ? 0 : undefined,
                        role: "option"
                    }));
                    // Render individual bar label if provided
                    if (pointData.barLabel && isLegendActive) {
                        barLabelsForGroup.push(/*#__PURE__*/ React.createElement("text", {
                            key: `${singleSet.indexNum}-${legendIndex}-${pointIndex}-label`,
                            x: xPoint + _barWidth / 2,
                            y: pointData.data >= Y_ORIGIN ? yPoint - 6 : yPoint + height + 12,
                            textAnchor: "middle",
                            className: classes.barLabel,
                            "aria-hidden": true,
                            style: {
                                direction: 'ltr',
                                unicodeBidi: 'isolate'
                            }
                        }, pointData.barLabel));
                    }
                    barTotalValue += pointData.data;
                });
                if (barTotalValue !== null && !props.hideLabels && Math.ceil(_barWidth) >= 16 && isLegendActive) {
                    barLabelsForGroup.push(/*#__PURE__*/ React.createElement("text", {
                        key: `${singleSet.indexNum}-${legendIndex}`,
                        x: xPoint + _barWidth / 2,
                        y: barTotalValue >= Y_ORIGIN ? yPositiveStart - 6 : yNegativeStart + 12,
                        textAnchor: "middle",
                        className: classes.barLabel,
                        "aria-hidden": true,
                        style: {
                            direction: 'ltr',
                            unicodeBidi: 'isolate'
                        }
                    }, typeof props.yAxisTickFormat === 'function' ? props.yAxisTickFormat(barTotalValue) : formatScientificLimitWidth(barTotalValue)));
                }
            }
        });
        const categoryGroupAriaLabel = `${singleSet.xAxisPoint}, category ${singleSet.indexNum + 1} of ${_datasetForBars.length}, with ${presentLegends.length} bars`;
        return /*#__PURE__*/ React.createElement("g", {
            role: "listbox",
            "aria-label": categoryGroupAriaLabel,
            key: singleSet.indexNum,
            transform: `translate(${xScale0(singleSet.xAxisPoint) + (xScale0.bandwidth() - effectiveGroupWidth) / 2}, 0)`
        }, singleGroup, barLabelsForGroup);
    };
    // For grouped vertical bar chart, First need to define total scale (from start to end)
    // From that need to define scale for single group of bars - done by createX1Scale
    const _createX0Scale = (containerWidth)=>{
        const x0Axis = d3ScaleBand().domain(xAxisLabels).range(_useRtl ? [
            containerWidth - _margins.right - _domainMargin,
            _margins.left + _domainMargin
        ] : [
            _margins.left + _domainMargin,
            containerWidth - _margins.right - _domainMargin
        ]).paddingInner(_xAxisInnerPadding).paddingOuter(_xAxisOuterPadding);
        return x0Axis;
    };
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const _createX1Scale = ()=>{
        return d3ScaleBand().domain(_barLegends)// When there is only one group, xScale0 adds padding around it,
        // causing the bandwidth to become smaller than the actual group width.
        // So to render bars in the group correctly, use groupWidth instead of the generated scale bandwidth.
        .range(_useRtl ? [
            _groupWidth,
            0
        ] : [
            0,
            _groupWidth
        ]).paddingInner(X1_INNER_PADDING);
    };
    const _onLegendHover = (legendTitle)=>{
        setActiveLegend(legendTitle);
    };
    const _onLegendLeave = ()=>{
        setActiveLegend('');
    };
    const _getAxisData = React.useCallback((yAxisData)=>{
        if (yAxisData && yAxisData.yAxisDomainValues.length) {
            const { yAxisDomainValues: domainValue } = yAxisData;
            _yMax = Math.max(domainValue[domainValue.length - 1], props.yMaxValue || 0);
        }
    }, [
        props.yMaxValue
    ]);
    /**
   * This function checks if the given legend is highlighted or not.
   * A legend can be highlighted in 2 ways:
   * 1. selection: if the user clicks on it
   * 2. hovering: if there is no selected legend and the user hovers over it
   */ const _legendHighlighted = (legendTitle)=>{
        return _getHighlightedLegend().includes(legendTitle);
    };
    /**
   * This function checks if none of the legends is selected or hovered.
   */ const _noLegendHighlighted = ()=>{
        return _getHighlightedLegend().length === 0;
    };
    const _getHighlightedLegend = ()=>{
        return selectedLegends.length > 0 ? selectedLegends : activeLegend ? [
            activeLegend
        ] : [];
    };
    const getAriaLabel = (point, xAxisPoint)=>{
        var _point_callOutAccessibilityData;
        const xValue = point.xAxisCalloutData || xAxisPoint;
        const legend = point.legend;
        const yValue = point.yAxisCalloutData || point.data;
        return ((_point_callOutAccessibilityData = point.callOutAccessibilityData) === null || _point_callOutAccessibilityData === void 0 ? void 0 : _point_callOutAccessibilityData.ariaLabel) || `${xValue}. ${legend}, ${yValue}.`;
    };
    const _getDomainMargins = (containerWidth)=>{
        /** Total width available to render the bars */ const totalWidth = calcTotalWidth(containerWidth, _margins, MIN_DOMAIN_MARGIN);
        if (_xAxisType === XAxisTypes.StringAxis) {
            if (isScalePaddingDefined(props.xAxisOuterPadding)) {
                // Setting the domain margin for string x-axis to 0 because the xAxisOuterPadding prop is now available
                // to adjust the space before the first group and after the last group.
                _domainMargin = 0;
            } else if (props.barWidth !== 'auto') {
                // Update the bar width so that when CartesianChart rerenders,
                // the following calculations don't use the previous bar width.
                _barWidth = getBarWidth(props.barWidth, props.maxBarWidth);
                const groupWidth = calcRequiredWidth(_barWidth, _barLegends.length, X1_INNER_PADDING);
                /** Total width required to render the groups. Directly proportional to group width */ const reqWidth = calcRequiredWidth(groupWidth, _xAxisLabels.length, _xAxisInnerPadding);
                if (totalWidth >= reqWidth) {
                    // Center align the chart by setting equal left and right margins for domain
                    _domainMargin = MIN_DOMAIN_MARGIN + (totalWidth - reqWidth) / 2;
                }
            } else if (props.mode === 'plotly' && xAxisLabels.length > 1) {
                // Calculate the remaining width after rendering groups at their maximum allowable width
                const groupBandwidth = calcBandwidth(totalWidth, _xAxisLabels.length, _xAxisInnerPadding);
                const barBandwidth = calcBandwidth(groupBandwidth, _barLegends.length, X1_INNER_PADDING);
                const barWidth = getBarWidth(props.barWidth, props.maxBarWidth, barBandwidth);
                const groupWidth = calcRequiredWidth(barWidth, _barLegends.length, X1_INNER_PADDING);
                let reqWidth = calcRequiredWidth(groupWidth, _xAxisLabels.length, _xAxisInnerPadding);
                const margin1 = (totalWidth - reqWidth) / 2;
                let margin2 = Number.POSITIVE_INFINITY;
                if (!props.hideTickOverlap) {
                    // Calculate the remaining width after accounting for the space required to render x-axis labels
                    const step = calculateLongestLabelWidth(_xAxisLabels) + 20;
                    reqWidth = (_xAxisLabels.length - _xAxisInnerPadding) * step;
                    margin2 = (totalWidth - reqWidth) / 2;
                }
                _domainMargin = MIN_DOMAIN_MARGIN + Math.max(0, Math.min(margin1, margin2));
            }
        }
        return {
            ..._margins,
            left: _margins.left + _domainMargin,
            right: _margins.right + _domainMargin
        };
    };
    const _isChartEmpty = (_barData, _lineData)=>{
        return !(_barData && _barData.length > 0 && _barData.filter((item)=>item.series.length).length > 0 || _lineData && _lineData.length > 0 && _lineData.some((series)=>series.data.length > 0));
    };
    const _getChartTitle = ()=>{
        return (props.chartTitle ? `${props.chartTitle}. ` : '') + `Vertical bar chart with ${_barLegends.length} grouped bar series` + (_lineLegends.length > 0 ? ` and ${_lineLegends.length} line series. ` : '. ');
    };
    const _createLines = (_lineData, xScale, yScalePrimary, yScaleSecondary)=>{
        const lineBorders = [];
        const lines = [];
        const dots = [];
        const scaleLineX = (x)=>xScale(x) + xScale.bandwidth() / 2;
        _lineData.forEach((series, seriesIdx)=>{
            var _series_lineOptions;
            const lineBorderGroup = [];
            const lineGroup = [];
            const dotGroup = [];
            const lineBorderWidth = ((_series_lineOptions = series.lineOptions) === null || _series_lineOptions === void 0 ? void 0 : _series_lineOptions.lineBorderWidth) ? Number.parseFloat(series.lineOptions.lineBorderWidth.toString()) : 0;
            const yScale = series.useSecondaryYScale && yScaleSecondary ? yScaleSecondary : yScalePrimary;
            const shouldHighlight = _legendHighlighted(series.legend) || _noLegendHighlighted();
            series.data.forEach((point, pointIdx)=>{
                const x2 = scaleLineX(point.x);
                const y2 = yScale(point.y);
                if (pointIdx > 0) {
                    var _series_lineOptions, _series_lineOptions1, _series_lineOptions2;
                    const x1 = scaleLineX(series.data[pointIdx - 1].x);
                    const y1 = yScale(series.data[pointIdx - 1].y);
                    if (lineBorderWidth > 0) {
                        var _series_lineOptions3;
                        var _series_lineOptions_lineBorderColor;
                        lineBorderGroup.push(/*#__PURE__*/ React.createElement("line", {
                            key: `lineBorder-${seriesIdx}-${pointIdx}`,
                            x1: x1,
                            y1: y1,
                            x2: x2,
                            y2: y2,
                            fill: "transparent",
                            stroke: (_series_lineOptions_lineBorderColor = (_series_lineOptions3 = series.lineOptions) === null || _series_lineOptions3 === void 0 ? void 0 : _series_lineOptions3.lineBorderColor) !== null && _series_lineOptions_lineBorderColor !== void 0 ? _series_lineOptions_lineBorderColor : tokens.colorNeutralBackground1,
                            strokeWidth: 3 + lineBorderWidth * 2,
                            strokeLinecap: "round",
                            opacity: shouldHighlight ? 1 : 0.1
                        }));
                    }
                    var _series_lineOptions_strokeWidth, _series_lineOptions_strokeLinecap;
                    lineGroup.push(/*#__PURE__*/ React.createElement("line", {
                        key: `line-${seriesIdx}-${pointIdx}`,
                        x1: x1,
                        y1: y1,
                        x2: x2,
                        y2: y2,
                        stroke: series.color,
                        strokeWidth: (_series_lineOptions_strokeWidth = (_series_lineOptions = series.lineOptions) === null || _series_lineOptions === void 0 ? void 0 : _series_lineOptions.strokeWidth) !== null && _series_lineOptions_strokeWidth !== void 0 ? _series_lineOptions_strokeWidth : 3,
                        strokeLinecap: (_series_lineOptions_strokeLinecap = (_series_lineOptions1 = series.lineOptions) === null || _series_lineOptions1 === void 0 ? void 0 : _series_lineOptions1.strokeLinecap) !== null && _series_lineOptions_strokeLinecap !== void 0 ? _series_lineOptions_strokeLinecap : 'round',
                        strokeDasharray: (_series_lineOptions2 = series.lineOptions) === null || _series_lineOptions2 === void 0 ? void 0 : _series_lineOptions2.strokeDasharray,
                        opacity: shouldHighlight ? 1 : 0.1,
                        onMouseOver: (e)=>_onLineHover(e, series, seriesIdx, pointIdx, scaleLineX),
                        onMouseLeave: _onBarLeave
                    }));
                }
                const dotId = _getDotId(seriesIdx, pointIdx);
                const isLinePointActive = activeLinePoint === point.x || activeLinePoint === dotId;
                dotGroup.push(/*#__PURE__*/ React.createElement("circle", {
                    key: dotId,
                    id: dotId,
                    cx: x2,
                    cy: y2,
                    r: shouldHighlight && isLinePointActive ? 8 : 0.3,
                    fill: tokens.colorNeutralBackground1,
                    stroke: series.color,
                    strokeWidth: 3,
                    opacity: shouldHighlight ? 1 : 0.1,
                    onMouseOver: (e)=>_onLineHover(e, series, seriesIdx, pointIdx, scaleLineX),
                    onMouseLeave: _onBarLeave,
                    tabIndex: shouldHighlight ? 0 : undefined,
                    onFocus: (e)=>_onLineFocus(e, series, seriesIdx, pointIdx),
                    onBlur: _onBarLeave,
                    role: "option",
                    "aria-label": getAriaLabel({
                        xAxisCalloutData: point.xAxisCalloutData,
                        legend: series.legend,
                        yAxisCalloutData: point.yAxisCalloutData,
                        data: point.y,
                        callOutAccessibilityData: point.callOutAccessibilityData
                    }, point.x)
                }));
            });
            const dotGroupAriaLabel = `${series.legend || `Line ${seriesIdx + 1}`}, line with ${series.data.length} data points`;
            lineBorders.push(/*#__PURE__*/ React.createElement("g", {
                key: `lineBorderGroup-${seriesIdx}`
            }, lineBorderGroup));
            lines.push(/*#__PURE__*/ React.createElement("g", {
                key: `lineGroup-${seriesIdx}`
            }, lineGroup));
            dots.push(/*#__PURE__*/ React.createElement("g", {
                role: "listbox",
                key: `dotGroup-${seriesIdx}`,
                "aria-label": dotGroupAriaLabel
            }, dotGroup));
        });
        return dots.length > 0 ? /*#__PURE__*/ React.createElement("g", null, lineBorders.length > 0 ? /*#__PURE__*/ React.createElement("g", null, lineBorders) : null, lines.length > 0 ? /*#__PURE__*/ React.createElement("g", null, lines) : null, /*#__PURE__*/ React.createElement("g", null, dots)) : null;
    };
    const _onLineHover = (event, series, seriesIdx, pointIdx, scaleLineX)=>{
        const pointerX = d3Pointer(event, _rectRef.current)[0];
        let closestPointIdx = pointIdx;
        if (pointIdx > 0) {
            const currPointPos = scaleLineX(series.data[pointIdx].x);
            const prevPointPos = scaleLineX(series.data[pointIdx - 1].x);
            if (Math.abs(prevPointPos - pointerX) < Math.abs(currPointPos - pointerX)) {
                closestPointIdx = pointIdx - 1;
            }
        }
        event.persist();
        _showCalloutForLines(event.currentTarget, series, seriesIdx, closestPointIdx);
    };
    const _onLineFocus = (event, series, seriesIdx, pointIdx)=>{
        _showCalloutForLines(event.currentTarget, series, seriesIdx, pointIdx);
    };
    const _showCalloutForLines = (target, series, seriesIdx, pointIdx)=>{
        const point = series.data[pointIdx];
        const pointData = {
            ...point,
            legend: series.legend,
            color: series.color,
            key: series.legend,
            data: point.y,
            yAxisCalloutData: point.yAxisCalloutData
        };
        const groupData = _datasetForBars.find((singleSet)=>singleSet.xAxisPoint === point.x);
        _showCallout(target, pointData, groupData, _getDotId(seriesIdx, pointIdx));
    };
    const _showCallout = (target, pointData, // eslint-disable-next-line @typescript-eslint/no-explicit-any
    groupData, _activeLinePoint = '')=>{
        setPopoverTarget(target);
        setPopoverOpen(_noLegendHighlighted() || _legendHighlighted(pointData.legend));
        setCalloutLegend(pointData.legend);
        setDataForHoverCard(pointData.data);
        setColor(pointData.color);
        var _pointData_xAxisCalloutData;
        setXCalloutValue((_pointData_xAxisCalloutData = pointData.xAxisCalloutData) !== null && _pointData_xAxisCalloutData !== void 0 ? _pointData_xAxisCalloutData : groupData.xAxisPoint);
        setYCalloutValue(pointData.yAxisCalloutData);
        setCallOutAccessibilityData(props.isCalloutForStack ? groupData.stackCallOutAccessibilityData : pointData.callOutAccessibilityData);
        setYValueHover(groupData.groupSeries.filter((item)=>_noLegendHighlighted() || _legendHighlighted(item.legend)));
        var _pointData_xAxisCalloutData1;
        setHoverXValue((_pointData_xAxisCalloutData1 = pointData.xAxisCalloutData) !== null && _pointData_xAxisCalloutData1 !== void 0 ? _pointData_xAxisCalloutData1 : groupData.xAxisPoint);
        setActiveLinePoint(props.isCalloutForStack ? groupData.xAxisPoint : _activeLinePoint);
    };
    const _getDotId = (seriesIdx, pointIdx)=>{
        return _uniqDotId + `-${seriesIdx}-${pointIdx}`;
    };
    return !_isChartEmpty(barData, lineData) ? /*#__PURE__*/ React.createElement(CartesianChart, {
        ...props,
        chartTitle: _getChartTitle(),
        points: _datasetForBars,
        chartType: ChartTypes.GroupedVerticalBarChart,
        getDomainNRangeValues: _getDomainNRangeValues,
        getMinMaxOfYAxis: _getMinMaxOfYAxis,
        createStringYAxis: createStringYAxis,
        calloutProps: calloutProps,
        legendBars: legendBars,
        xAxisType: _xAxisType,
        createYAxis: createNumericYAxis,
        datasetForXAxisDomain: _xAxisLabels,
        tickParams: tickParams,
        tickPadding: props.tickPadding || 5,
        maxOfYVal: _yMax,
        getmargins: _getMargins,
        getGraphData: _getGraphData,
        getAxisData: _getAxisData,
        onChartMouseLeave: _handleChartMouseLeave,
        getDomainMargins: _getDomainMargins,
        ..._xAxisType === XAxisTypes.StringAxis && {
            xAxisInnerPadding: _xAxisInnerPadding,
            xAxisOuterPadding: _xAxisOuterPadding
        },
        barwidth: _barWidth,
        componentRef: cartesianChartRef,
        /* eslint-disable react/jsx-no-bind */ children: (childProps)=>{
            return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("rect", {
                ref: _rectRef,
                width: "100%",
                height: "100%",
                fill: "transparent",
                style: {
                    pointerEvents: 'none'
                }
            }), /*#__PURE__*/ React.createElement("g", null, _groupedVerticalBarGraph), _createLines(lineData, childProps.xScale, childProps.yScalePrimary, childProps.yScaleSecondary));
        }
    }) : /*#__PURE__*/ React.createElement("div", {
        id: _emptyChartId,
        role: 'alert',
        style: {
            opacity: '0'
        },
        "aria-label": 'Graph has no data to display'
    });
});
GroupedVerticalBarChart.displayName = 'GroupedVerticalBarChart';
