'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "GanttChart", {
    enumerable: true,
    get: function() {
        return GanttChart;
    }
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _d3array = require("d3-array");
const _reactutilities = require("@fluentui/react-utilities");
const _index = require("../Legends/index");
const _index1 = require("../CommonComponents/index");
const _ChartPopover = require("../CommonComponents/ChartPopover");
const _index2 = require("../../utilities/index");
const _chartutilities = require("@fluentui/chart-utilities");
const _hooks = require("../../utilities/hooks");
const DEFAULT_BAR_HEIGHT = 24;
const MIN_BAR_HEIGHT = 1;
const GanttChart = /*#__PURE__*/ _react.forwardRef(({ useUTC = true, yAxisCategoryOrder = 'default', maxBarHeight = 24, ...props }, forwardedRef)=>{
    var _props_legendProps;
    const _barHeight = _react.useRef(DEFAULT_BAR_HEIGHT);
    const _margins = _react.useRef({});
    const _calloutAnchorPoint = _react.useRef(null);
    const _emptyChartId = (0, _reactutilities.useId)('Gantt_empty');
    const _legendId = (0, _reactutilities.useId)('gantt_legend');
    const _legendMap = _react.useRef({});
    const _prevProps = _react.useRef({});
    const [calloutColor, setCalloutColor] = _react.useState('');
    const [hoveredLegend, setHoveredLegend] = _react.useState('');
    const [calloutLegend, setCalloutLegend] = _react.useState('');
    const [xCalloutValue, setXCalloutValue] = _react.useState('');
    const [yCalloutValue, setYCalloutValue] = _react.useState('');
    const [selectedLegends, setSelectedLegends] = _react.useState(((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends) || []);
    const [calloutDataPoint, setCalloutDataPoint] = _react.useState();
    const [clickPosition, setClickPosition] = _react.useState({
        x: 0,
        y: 0
    });
    const [isPopoverOpen, setPopoverOpen] = _react.useState(false);
    const { cartesianChartRef, legendsRef: _legendsRef } = (0, _hooks.useImageExport)(props.componentRef, props.hideLegend);
    _react.useEffect(()=>{
        var _prevProps_current_legendProps, _props_legendProps;
        if (!(0, _index2.areArraysEqual)((_prevProps_current_legendProps = _prevProps.current.legendProps) === null || _prevProps_current_legendProps === void 0 ? void 0 : _prevProps_current_legendProps.selectedLegends, (_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends)) {
            var _props_legendProps1;
            setSelectedLegends(((_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.selectedLegends) || []);
        }
        _prevProps.current = props;
    }, [
        props
    ]);
    const _points = _react.useMemo(()=>{
        var _props_data;
        _legendMap.current = {};
        let colorIndex = 0;
        var _props_data_map;
        return (_props_data_map = (_props_data = props.data) === null || _props_data === void 0 ? void 0 : _props_data.map((point)=>{
            const legend = `${point.legend}`;
            if (!_legendMap.current[legend]) {
                let startColor = point.color ? (0, _index2.getColorFromToken)(point.color) : (0, _index2.getNextColor)(colorIndex, 0);
                let endColor = startColor;
                if (props.enableGradient) {
                    var _point_gradient, _point_gradient1;
                    startColor = (_point_gradient = point.gradient) === null || _point_gradient === void 0 ? void 0 : _point_gradient[0];
                    endColor = (_point_gradient1 = point.gradient) === null || _point_gradient1 === void 0 ? void 0 : _point_gradient1[1];
                }
                _legendMap.current[legend] = {
                    id: `${_legendId}_${colorIndex}`,
                    startColor,
                    endColor
                };
                colorIndex += 1;
            }
            const { startColor, endColor } = _legendMap.current[legend];
            return {
                ...point,
                color: startColor,
                ...props.enableGradient ? {
                    gradient: [
                        startColor,
                        endColor
                    ]
                } : {}
            };
        })) !== null && _props_data_map !== void 0 ? _props_data_map : [];
    }, [
        props.data,
        props.enableGradient
    ]);
    const _xAxisType = _react.useMemo(()=>{
        if (_points.length > 0) {
            return (0, _index2.getTypeOfAxis)(_points[0].x.start, true);
        }
        return _index2.XAxisTypes.DateAxis;
    }, [
        _points
    ]);
    const _yAxisType = _react.useMemo(()=>{
        if (_points.length > 0) {
            return (0, _index2.getTypeOfAxis)(_points[0].y, false);
        }
        return _index2.YAxisType.StringAxis;
    }, [
        _points
    ]);
    const _yAxisPadding = _react.useMemo(()=>{
        return (0, _index2.getScalePadding)(props.yAxisPadding, undefined, 1 / 2);
    }, [
        props.yAxisPadding
    ]);
    const _dateFormatOptions = _react.useMemo(()=>{
        if (_xAxisType !== _index2.XAxisTypes.DateAxis) {
            return undefined;
        }
        let lowestFormatLevel = 100;
        let highestFormatLevel = -1;
        _points.forEach((p)=>{
            const startFormatLevel = (0, _index2.getDateFormatLevel)(p.x.start, useUTC);
            const endFormatLevel = (0, _index2.getDateFormatLevel)(p.x.end, useUTC);
            lowestFormatLevel = Math.min(lowestFormatLevel, startFormatLevel, endFormatLevel);
            highestFormatLevel = Math.max(highestFormatLevel, startFormatLevel, endFormatLevel);
        });
        return (0, _chartutilities.getMultiLevelDateTimeFormatOptions)(lowestFormatLevel, highestFormatLevel);
    }, [
        useUTC,
        _points,
        _xAxisType
    ]);
    const _mapYValueToXValues = _react.useCallback(()=>{
        const yValueToXValues = {};
        _points.forEach((point)=>{
            if (!yValueToXValues[point.y]) {
                yValueToXValues[point.y] = [];
            }
            yValueToXValues[point.y].push(+point.x.end - +point.x.start);
        });
        return yValueToXValues;
    }, [
        _points
    ]);
    const _getOrderedYAxisLabels = _react.useCallback(()=>{
        const yValueToXValues = _mapYValueToXValues();
        if (_yAxisType !== _index2.YAxisType.StringAxis) {
            return Object.keys(yValueToXValues).sort((a, b)=>+a - +b);
        }
        if (yAxisCategoryOrder === 'default') {
            return Object.keys(yValueToXValues).reverse();
        }
        return (0, _index2.sortAxisCategories)(yValueToXValues, yAxisCategoryOrder);
    }, [
        _mapYValueToXValues,
        _yAxisType,
        yAxisCategoryOrder
    ]);
    const _yAxisLabels = _react.useMemo(()=>_getOrderedYAxisLabels(), [
        _getOrderedYAxisLabels
    ]);
    const _getDomainNRangeValues = _react.useCallback((points, margins, containerWidth, chartType, isRTL, xAxisType, barWidth, tickValues)=>{
        const xValues = [];
        points.forEach((point)=>{
            xValues.push(point.x.start, point.x.end);
        });
        const xMin = (0, _d3array.min)(xValues) || 0;
        const xMax = (0, _d3array.max)(xValues) || 0;
        return {
            dStartValue: isRTL ? xMax : xMin,
            dEndValue: isRTL ? xMin : xMax,
            rStartValue: margins.left,
            rEndValue: containerWidth - margins.right
        };
    }, []);
    const _getMargins = _react.useCallback((margins)=>{
        _margins.current = margins;
    }, []);
    const _getFormattedXValue = _react.useCallback((point)=>{
        let formattedStartX;
        let formattedEndX;
        if (_xAxisType === _index2.XAxisTypes.DateAxis) {
            formattedStartX = (0, _chartutilities.formatDateToLocaleString)(point.x.start, props.culture, useUTC, false, _dateFormatOptions);
            formattedEndX = (0, _chartutilities.formatDateToLocaleString)(point.x.end, props.culture, useUTC, false, _dateFormatOptions);
        } else {
            formattedStartX = point.x.start.toString();
            formattedEndX = point.x.end.toString();
        }
        return `${formattedStartX} - ${formattedEndX}`;
    }, [
        props.culture,
        useUTC,
        _dateFormatOptions,
        _xAxisType
    ]);
    const _getCustomizedCallout = _react.useCallback(()=>{
        const defaultRender = (point)=>{
            return point ? /*#__PURE__*/ _react.createElement(_ChartPopover.ChartPopover, {
                isPopoverOpen: isPopoverOpen,
                clickPosition: clickPosition,
                XValue: point.yAxisCalloutData || point.y.toString(),
                legend: point.legend,
                YValue: point.xAxisCalloutData || _getFormattedXValue(point),
                color: point.color,
                culture: props.culture
            }) : null;
        };
        return props.onRenderCalloutPerDataPoint ? props.onRenderCalloutPerDataPoint(calloutDataPoint, defaultRender) : null;
    //eslint-disable-next-line react-hooks/exhaustive-deps
    }, [
        _getFormattedXValue,
        calloutDataPoint,
        props.culture,
        props.onRenderCalloutPerDataPoint
    ]);
    const _getAriaLabel = _react.useCallback((point)=>{
        var _point_callOutAccessibilityData;
        const xValue = point.xAxisCalloutData || _getFormattedXValue(point);
        const yValue = point.yAxisCalloutData || point.y;
        return ((_point_callOutAccessibilityData = point.callOutAccessibilityData) === null || _point_callOutAccessibilityData === void 0 ? void 0 : _point_callOutAccessibilityData.ariaLabel) || `${yValue}. ` + (point.legend ? `${point.legend}, ` : '') + `${xValue}.`;
    }, [
        _getFormattedXValue
    ]);
    const _getHighlightedLegend = _react.useCallback(()=>{
        return selectedLegends.length > 0 ? selectedLegends : hoveredLegend ? [
            hoveredLegend
        ] : [];
    }, [
        hoveredLegend,
        selectedLegends
    ]);
    /**
     * 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 = _react.useCallback((legend)=>{
        return _getHighlightedLegend().includes(`${legend}`);
    }, [
        _getHighlightedLegend
    ]);
    /**
     * This function checks if none of the legends is selected or hovered.
     */ const _noLegendHighlighted = _react.useCallback(()=>{
        return _getHighlightedLegend().length === 0;
    }, [
        _getHighlightedLegend
    ]);
    const _showCallout = _react.useCallback((target, point)=>{
        if (!(_noLegendHighlighted() || _legendHighlighted(point.legend)) || _calloutAnchorPoint.current === point) {
            return;
        }
        if ('clientX' in target && 'clientY' in target) {
            updatePosition(target.clientX, target.clientY);
        } else {
            const rect = target.target.getBoundingClientRect();
            updatePosition(rect.left, rect.top);
        }
        _calloutAnchorPoint.current = point;
        setPopoverOpen(true);
        setCalloutLegend(point.legend);
        setCalloutColor(point.color);
        setXCalloutValue(point.yAxisCalloutData || point.y.toString());
        setYCalloutValue(point.xAxisCalloutData || _getFormattedXValue(point));
        setCalloutDataPoint(point);
    }, [
        _getFormattedXValue,
        _legendHighlighted,
        _noLegendHighlighted
    ]);
    const _onBarFocus = _react.useCallback((point, focusEvent)=>{
        _showCallout(focusEvent, point);
    }, [
        _showCallout
    ]);
    const _onBarHover = _react.useCallback((point, mouseEvent)=>{
        _showCallout(mouseEvent, point);
    }, [
        _showCallout
    ]);
    const _onBarLeave = _react.useCallback(()=>{
    // do nothing
    }, []);
    const _handleChartMouseLeave = _react.useCallback(()=>{
        _calloutAnchorPoint.current = null;
        setPopoverOpen(false);
        setCalloutLegend('');
        setCalloutColor('');
        setXCalloutValue('');
        setYCalloutValue('');
        setCalloutDataPoint(undefined);
    }, []);
    const _getBarHeight = _react.useCallback((adjustedValue)=>{
        let barHeight;
        if (typeof props.barHeight === 'number') {
            barHeight = props.barHeight;
        } else {
            barHeight = adjustedValue;
        }
        if (typeof maxBarHeight === 'number') {
            barHeight = Math.min(barHeight, maxBarHeight);
        }
        barHeight = Math.max(barHeight, MIN_BAR_HEIGHT);
        return barHeight;
    }, [
        maxBarHeight,
        props.barHeight
    ]);
    const _getOrderedDataPoints = _react.useCallback(()=>{
        const result = [];
        const yValueToPoints = {};
        _points.forEach((point)=>{
            if (!yValueToPoints[point.y]) {
                yValueToPoints[point.y] = [];
            }
            yValueToPoints[point.y].push(point);
        });
        for(let i = _yAxisLabels.length - 1; i >= 0; i--){
            const yValue = _yAxisLabels[i];
            if (yValueToPoints[yValue]) {
                result.push(...yValueToPoints[yValue].sort((a, b)=>+a.x.start - +b.x.start));
            }
        }
        return result;
    }, [
        _points,
        _yAxisLabels
    ]);
    const _createBars = _react.useCallback(({ xScale, yScalePrimary: yScale })=>{
        const getGradientId = (legend)=>{
            const legendId = _legendMap.current[`${legend}`].id;
            return `${legendId}_gradient`;
        };
        const gradientDefs = [];
        if (props.enableGradient) {
            Object.keys(_legendMap.current).forEach((legend, index)=>{
                const { startColor, endColor } = _legendMap.current[legend];
                gradientDefs.push(/*#__PURE__*/ _react.createElement("linearGradient", {
                    key: index,
                    id: getGradientId(legend)
                }, /*#__PURE__*/ _react.createElement("stop", {
                    offset: "0",
                    stopColor: startColor
                }), /*#__PURE__*/ _react.createElement("stop", {
                    offset: "100%",
                    stopColor: endColor
                })));
            });
        }
        let scaleBandwidth = 0;
        if (_yAxisType === _index2.YAxisType.StringAxis) {
            scaleBandwidth = yScale.bandwidth();
            _barHeight.current = _getBarHeight(scaleBandwidth);
        }
        const points = _getOrderedDataPoints();
        const bars = points.map((point, index)=>{
            const rectStartX = xScale(point.x.start);
            const rectEndX = xScale(point.x.end);
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const rectY = yScale(point.y) + (scaleBandwidth - _barHeight.current) / 2;
            const shouldHighlight = _noLegendHighlighted() || _legendHighlighted(point.legend);
            return /*#__PURE__*/ _react.createElement("rect", {
                key: index,
                x: Math.min(rectStartX, rectEndX),
                y: rectY,
                width: Math.max(Math.abs(rectEndX - rectStartX), 2),
                height: _barHeight.current,
                rx: props.roundCorners ? 3 : 0,
                fill: props.enableGradient ? `url(#${getGradientId(point.legend)})` : point.color,
                opacity: shouldHighlight ? 1 : 0.1,
                onClick: point.onClick,
                onMouseOver: (event)=>_onBarHover(point, event),
                onMouseLeave: _onBarLeave,
                onFocus: (event)=>_onBarFocus(point, event),
                onBlur: _onBarLeave,
                tabIndex: shouldHighlight ? 0 : -1,
                role: "img",
                "aria-label": _getAriaLabel(point)
            });
        });
        return /*#__PURE__*/ _react.createElement("g", null, gradientDefs.length > 0 ? /*#__PURE__*/ _react.createElement("defs", null, gradientDefs) : null, bars);
    }, [
        _getAriaLabel,
        _getBarHeight,
        _getOrderedDataPoints,
        _legendHighlighted,
        _noLegendHighlighted,
        _onBarFocus,
        _onBarHover,
        _onBarLeave,
        _yAxisType,
        props.enableGradient,
        props.roundCorners
    ]);
    const _onLegendHover = _react.useCallback((legend)=>{
        setHoveredLegend(legend);
    }, []);
    const _onLegendLeave = _react.useCallback(()=>{
        setHoveredLegend('');
    }, []);
    const _onLegendSelectionChange = _react.useCallback((_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);
        }
    }, [
        props.legendProps
    ]);
    const _getLegendData = _react.useCallback(()=>{
        const actions = [];
        Object.keys(_legendMap.current).forEach((legendTitle)=>{
            const legend = {
                title: legendTitle,
                color: _legendMap.current[legendTitle].startColor,
                hoverAction: ()=>{
                    _handleChartMouseLeave();
                    _onLegendHover(legendTitle);
                },
                onMouseOutAction: ()=>{
                    _onLegendLeave();
                }
            };
            actions.push(legend);
        });
        const legends = /*#__PURE__*/ _react.createElement(_index.Legends, {
            legends: actions,
            enabledWrapLines: props.enabledLegendsWrapLines,
            overflowText: props.legendsOverflowText,
            onChange: _onLegendSelectionChange,
            ...props.legendProps,
            legendRef: _legendsRef
        });
        return legends;
    }, [
        _handleChartMouseLeave,
        _onLegendHover,
        _onLegendLeave,
        _onLegendSelectionChange,
        props.enabledLegendsWrapLines,
        props.legendProps,
        props.legendsOverflowText
    ]);
    const _getChartTitle = _react.useCallback(()=>{
        return (props.chartTitle ? `${props.chartTitle}. ` : '') + `Gantt chart with ${_points.length} data points. `;
    }, [
        _points.length,
        props.chartTitle
    ]);
    const _isChartEmpty = _react.useCallback(()=>{
        return _points.length === 0;
    }, [
        _points.length
    ]);
    const _getYDomainMargins = _react.useCallback((containerHeight)=>{
        let domainMargin = _index2.MIN_DOMAIN_MARGIN;
        const ySet = new Set();
        _points.forEach((point)=>{
            ySet.add(point.y);
        });
        const uniqueY = Array.from(ySet);
        /** Total height available to render the bars */ const totalHeight = containerHeight - (_margins.current.top + _index2.MIN_DOMAIN_MARGIN) - (_margins.current.bottom + _index2.MIN_DOMAIN_MARGIN);
        if (_yAxisType !== _index2.YAxisType.StringAxis) {
            _barHeight.current = _getBarHeight((0, _index2.calculateAppropriateBarWidth)(uniqueY, totalHeight, _yAxisPadding));
            domainMargin += _barHeight.current / 2;
        }
        return {
            ..._margins.current,
            top: _margins.current.top + domainMargin,
            bottom: _margins.current.bottom + domainMargin
        };
    }, [
        _getBarHeight,
        _points,
        _yAxisPadding,
        _yAxisType
    ]);
    function updatePosition(newX, newY) {
        const threshold = 1; // Set a threshold for movement
        const { x, y } = clickPosition;
        // Calculate the distance moved
        const distance = Math.sqrt(Math.pow(newX - x, 2) + Math.pow(newY - y, 2));
        // Update the position only if the distance moved is greater than the threshold
        if (distance > threshold) {
            setClickPosition({
                x: newX,
                y: newY
            });
            setPopoverOpen(true);
        }
    }
    if (!_isChartEmpty()) {
        _barHeight.current = _getBarHeight(DEFAULT_BAR_HEIGHT);
        const calloutProps = {
            isPopoverOpen,
            clickPosition,
            color: calloutColor,
            legend: calloutLegend,
            XValue: xCalloutValue,
            YValue: yCalloutValue,
            ...props.calloutProps
        };
        const tickParams = {
            tickValues: props.tickValues,
            tickFormat: props.tickFormat
        };
        return /*#__PURE__*/ _react.createElement(_index1.CartesianChart, {
            ...props,
            yAxisPadding: _yAxisPadding,
            chartTitle: _getChartTitle(),
            points: _points,
            chartType: _index2.ChartTypes.GanttChart,
            xAxisType: _xAxisType,
            yAxisType: _yAxisType,
            componentRef: cartesianChartRef,
            stringDatasetForYAxisDomain: _yAxisLabels,
            calloutProps: calloutProps,
            tickParams: tickParams,
            legendBars: _getLegendData(),
            createYAxis: _index2.createYAxisForHorizontalBarChartWithAxis,
            getDomainNRangeValues: _getDomainNRangeValues,
            createStringYAxis: _index2.createStringYAxisForHorizontalBarChartWithAxis,
            getMinMaxOfYAxis: _index2.findHBCWANumericMinMaxOfY,
            customizedCallout: _getCustomizedCallout(),
            getmargins: _getMargins,
            getYDomainMargins: _getYDomainMargins,
            onChartMouseLeave: _handleChartMouseLeave,
            useUTC: useUTC,
            children: _createBars
        });
    } else {
        return /*#__PURE__*/ _react.createElement("div", {
            id: _emptyChartId,
            role: 'alert',
            style: {
                opacity: '0'
            },
            "aria-label": 'Graph has no data to display'
        });
    }
});
GanttChart.displayName = 'GanttChart';
