'use client';
import * as React from 'react';
import { useId } from '@fluentui/react-utilities';
import { useRtl } from '../../utilities/index';
import { Legends } from '../Legends/index';
import { useArrowNavigationGroup } from '@fluentui/react-tabster';
import { ChartPopover } from '../CommonComponents/ChartPopover';
import { formatToLocaleString } from '@fluentui/chart-utilities';
import { getContrastTextColor } from '../../utilities/colors';
import { useFunnelChartStyles } from './useFunnelChartStyles.styles';
import { getHorizontalFunnelSegmentGeometry, getVerticalFunnelSegmentGeometry, getSegmentTextProps, getStackedHorizontalFunnelSegmentGeometry, getStackedVerticalFunnelSegmentGeometry } from './funnelGeometry';
import { useImageExport } from '../../utilities/hooks';
export const FunnelChart = /*#__PURE__*/ React.forwardRef(({ orientation = 'vertical', ...restProps }, forwardedRef)=>{
    var _props_legendProps;
    const props = {
        orientation,
        ...restProps
    };
    const _emptyChartId = useId('_FunnelChart_empty');
    const isRTL = useRtl();
    const [hoveredStage, setHoveredStage] = React.useState(null);
    const [calloutData, setCalloutData] = React.useState(null);
    const [selectedLegends, setSelectedLegends] = React.useState([]);
    const [isPopoverOpen, setPopoverOpen] = React.useState(false);
    const [refSelected, setRefSelected] = React.useState(null);
    const isStacked = isStackedFunnelData(props.data);
    const { chartContainerRef, legendsRef: _legendsRef } = useImageExport(props.componentRef, props.hideLegend, false);
    React.useEffect(()=>{
        var _props_legendProps;
        if ((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends) {
            setSelectedLegends(props.legendProps.selectedLegends);
        }
    }, [
        (_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends
    ]);
    function _handleHover(data, mouseEvent, targetElement) {
        mouseEvent === null || mouseEvent === void 0 ? void 0 : mouseEvent.persist();
        setCalloutData(data);
        setRefSelected(targetElement);
        setPopoverOpen(true);
    }
    function _handleFocus(data, focusEvent, targetElement) {
        focusEvent === null || focusEvent === void 0 ? void 0 : focusEvent.persist();
        setCalloutData(data);
        setRefSelected(targetElement);
        setPopoverOpen(true);
    }
    function _handleStackedHover(stage, subValue, mouseEvent, targetElement) {
        mouseEvent === null || mouseEvent === void 0 ? void 0 : mouseEvent.persist();
        setCalloutData({
            stage,
            value: subValue.value,
            color: subValue.color,
            category: subValue.category
        });
        setRefSelected(targetElement);
        setPopoverOpen(true);
    }
    function _handleStackedFocus(stage, subValue, focusEvent, targetElement) {
        focusEvent === null || focusEvent === void 0 ? void 0 : focusEvent.persist();
        setCalloutData({
            stage,
            value: subValue.value,
            color: subValue.color,
            category: subValue.category
        });
        setRefSelected(targetElement);
        setPopoverOpen(true);
    }
    function _handleMouseOut() {
        setHoveredStage(null);
        setPopoverOpen(false);
        setCalloutData(null);
    }
    function _onLegendSelectionChange(legendsSelected, event, currentLegend) {
        var _props_legendProps, _props_legendProps1;
        if ((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.canSelectMultipleLegends) {
            setSelectedLegends(legendsSelected);
        } else {
            setSelectedLegends(legendsSelected.slice(-1));
        }
        if ((_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.onChange) {
            props.legendProps.onChange(legendsSelected, event, currentLegend);
        }
    }
    const _onLegendSelectionChangeCallback = React.useCallback(_onLegendSelectionChange, [
        props.legendProps
    ]);
    function getHighlightedLegend() {
        return selectedLegends.length > 0 ? selectedLegends : hoveredStage ? [
            hoveredStage
        ] : [];
    }
    function legendHighlighted(legend) {
        return getHighlightedLegend().includes(legend);
    }
    function noLegendHighlighted() {
        return getHighlightedLegend().length === 0;
    }
    function _getEventHandlerProps(data, opacity, segmentId) {
        const targetElement = document.getElementById(segmentId);
        if ('subValue' in data) {
            return {
                culture: props.culture,
                onMouseOver: opacity == 1 ? (event)=>_handleStackedHover(data.stage, data.subValue, event, targetElement) : undefined,
                onMouseMove: opacity == 1 ? (event)=>_handleStackedHover(data.stage, data.subValue, event, targetElement) : undefined,
                onFocus: (event)=>_handleStackedFocus(data.stage, data.subValue, event, targetElement),
                onBlur: ()=>_handleMouseOut(),
                onMouseOut: ()=>_handleMouseOut()
            };
        } else {
            return {
                culture: props.culture,
                onMouseOver: opacity == 1 ? (event)=>_handleHover(data, event, targetElement) : undefined,
                onMouseMove: opacity == 1 ? (event)=>_handleHover(data, event, targetElement) : undefined,
                onFocus: (event)=>_handleFocus(data, event, targetElement),
                onBlur: ()=>_handleMouseOut(),
                onMouseOut: ()=>_handleMouseOut()
            };
        }
    }
    function _renderSegmentText({ show, x, y, value, textColor, opacity }) {
        if (!show) {
            return null;
        }
        const textElement = /*#__PURE__*/ React.createElement("text", {
            x: isRTL ? funnelWidth - x : x,
            y: y,
            opacity: opacity,
            textAnchor: "middle",
            alignmentBaseline: "middle",
            fill: textColor
        }, formatToLocaleString(value.toString(), props.culture));
        if (isRTL) {
            return /*#__PURE__*/ React.createElement("g", {
                transform: `scale(-1,1) translate(${-funnelWidth},0)`
            }, textElement);
        }
        return textElement;
    }
    function _renderFunnelSegment({ key, pathD, fill, opacity, textProps, data, tabIndex }) {
        const segmentId = `funnel-segment-${key}`;
        const eventHandlers = _getEventHandlerProps(data, opacity, segmentId);
        const textColor = getContrastTextColor(fill);
        return /*#__PURE__*/ React.createElement("g", {
            key: key
        }, /*#__PURE__*/ React.createElement("path", {
            id: segmentId,
            d: pathD,
            fill: fill,
            opacity: opacity,
            ...eventHandlers,
            tabIndex: tabIndex
        }), textProps && /*#__PURE__*/ React.createElement("g", eventHandlers, _renderSegmentText({
            ...textProps,
            textColor,
            opacity
        })));
    }
    function _createFunnel(containerHeight, containerWidth) {
        const { data } = props;
        const funnelWidth = containerWidth;
        const funnelHeight = containerHeight * 0.8;
        return data.map((d, i)=>{
            const geometryProps = props.orientation === 'vertical' ? getVerticalFunnelSegmentGeometry({
                d,
                i,
                data,
                funnelWidth,
                funnelHeight,
                isRTL
            }) : getHorizontalFunnelSegmentGeometry({
                d,
                i,
                data,
                funnelWidth,
                funnelHeight,
                isRTL
            });
            const { pathD, textX, textY, availableWidth } = geometryProps;
            const minTextWidth = 16;
            const eventHandlerProps = _getEventHandlerProps(d);
            const textProps = getSegmentTextProps({
                availableWidth,
                minTextWidth,
                textX,
                textY,
                value: d.value,
                ...eventHandlerProps
            });
            return _renderFunnelSegment({
                key: i,
                pathD,
                fill: d.color,
                opacity: legendHighlighted(d.stage) || noLegendHighlighted() ? 1 : 0.1,
                textProps,
                data: d,
                tabIndex: legendHighlighted(d.stage) || noLegendHighlighted() ? 0 : undefined
            });
        });
    }
    function isStackedFunnelData(data) {
        return Array.isArray(data) && data.every((stage)=>Array.isArray(stage.subValues));
    }
    function _renderStackedSegment(stage, subValue, stageIndex, subValueIndex, geometryParams) {
        // Ensure stages have subValues for geometry functions
        const stagesWithSubValues = geometryParams.stages.map((s)=>({
                ...s,
                subValues: s.subValues || []
            }));
        const geom = props.orientation === 'vertical' ? getStackedVerticalFunnelSegmentGeometry({
            ...geometryParams,
            stages: stagesWithSubValues,
            i: stageIndex,
            k: subValueIndex
        }) : getStackedHorizontalFunnelSegmentGeometry({
            ...geometryParams,
            stages: stagesWithSubValues,
            i: stageIndex,
            k: subValueIndex
        });
        const minTextWidth = 16;
        const eventHandlerProps = _getEventHandlerProps({
            stage: stage.stage,
            subValue
        });
        const textProps = getSegmentTextProps({
            availableWidth: geom.availableWidth,
            minTextWidth,
            textX: geom.textX,
            textY: geom.textY,
            value: subValue.value,
            ...eventHandlerProps
        });
        return _renderFunnelSegment({
            key: `${stageIndex}-${subValueIndex}`,
            pathD: geom.pathD,
            fill: subValue.color,
            opacity: isStackedFunnelData(props.data) && legendHighlighted(subValue.category) || noLegendHighlighted() ? 1 : 0.1,
            textProps,
            data: {
                stage: stage.stage,
                subValue
            },
            tabIndex: legendHighlighted(subValue.category) || noLegendHighlighted() ? 0 : undefined
        });
    }
    function _createStackedFunnel(containerHeight, containerWidth) {
        const { data } = props;
        const stages = data;
        const totals = stages.map((s)=>{
            var _s_subValues;
            var _s_subValues_reduce;
            return (_s_subValues_reduce = s === null || s === void 0 ? void 0 : (_s_subValues = s.subValues) === null || _s_subValues === void 0 ? void 0 : _s_subValues.reduce((sum, subValue)=>sum + subValue.value, 0)) !== null && _s_subValues_reduce !== void 0 ? _s_subValues_reduce : 0;
        });
        const maxTotal = Math.max(...totals);
        const funnelWidth = containerWidth;
        const funnelHeight = containerHeight * 0.8;
        const paths = [];
        const geometryParams = {
            stages,
            totals,
            maxTotal,
            funnelWidth,
            funnelHeight,
            isRTL
        };
        for(let i = 0; i < stages.length; i++){
            const cur = stages[i];
            var _cur_subValues;
            for(let k = 0; k < ((_cur_subValues = cur.subValues) !== null && _cur_subValues !== void 0 ? _cur_subValues : []).length; k++){
                var _cur_subValues1;
                const v = (_cur_subValues1 = cur.subValues) === null || _cur_subValues1 === void 0 ? void 0 : _cur_subValues1[k];
                if (!v) {
                    continue;
                }
                paths.push(_renderStackedSegment(cur, v, i, k, geometryParams));
            }
        }
        return paths;
    }
    function _renderLegends() {
        if (props.hideLegend) {
            return /*#__PURE__*/ React.createElement(React.Fragment, null);
        }
        let legends;
        if (isStacked) {
            // Collect unique categories and their color
            const categoryMap = {};
            props.data.forEach((stage)=>{
                (stage.subValues || []).forEach((sub)=>{
                    if (!(sub.category in categoryMap)) {
                        categoryMap[sub.category] = sub.color;
                    }
                });
            });
            legends = Object.entries(categoryMap).map(([category, color])=>({
                    title: category,
                    color,
                    hoverAction: ()=>setHoveredStage(category),
                    onMouseOutAction: ()=>setHoveredStage(null)
                }));
        } else {
            legends = props.data.map((d)=>({
                    title: d.stage,
                    color: d.color,
                    hoverAction: ()=>setHoveredStage(d.stage),
                    onMouseOutAction: ()=>setHoveredStage(null)
                }));
        }
        return /*#__PURE__*/ React.createElement("div", {
            style: {
                display: 'flex',
                justifyContent: 'center'
            }
        }, /*#__PURE__*/ React.createElement(Legends, {
            legends: legends,
            centerLegends: true,
            onChange: _onLegendSelectionChangeCallback,
            ...props.legendProps,
            legendRef: _legendsRef
        }));
    }
    function _isChartEmpty() {
        return !(props.data && props.data.length > 0);
    }
    const classes = useFunnelChartStyles(props);
    const calloutProps = {
        ...props.calloutProps,
        color: calloutData === null || calloutData === void 0 ? void 0 : calloutData.color,
        hoverXValue: calloutData === null || calloutData === void 0 ? void 0 : calloutData.stage,
        YValue: calloutData === null || calloutData === void 0 ? void 0 : calloutData.value
    };
    const width = props.width || 350;
    const height = props.height || 500;
    const funnelMarginTop = 40;
    const funnelWidth = width * 0.8;
    const funnelOffsetX = (width - funnelWidth) / 2;
    const arrowAttributes = useArrowNavigationGroup({
        circular: true,
        axis: 'horizontal'
    });
    return !_isChartEmpty() ? /*#__PURE__*/ React.createElement("div", {
        ref: chartContainerRef,
        className: classes.root,
        ...arrowAttributes,
        style: {
            width,
            height
        }
    }, /*#__PURE__*/ React.createElement("svg", {
        width: width,
        height: height,
        className: classes.chart,
        role: 'img',
        "aria-label": props.chartTitle
    }, /*#__PURE__*/ React.createElement("g", {
        transform: isRTL ? `translate(${funnelOffsetX + funnelWidth}, ${funnelMarginTop}) scale(-1,1)` : `translate(${funnelOffsetX}, ${funnelMarginTop})`
    }, isStacked ? _createStackedFunnel(height - funnelMarginTop, funnelWidth) : _createFunnel(height - funnelMarginTop, funnelWidth))), isPopoverOpen && /*#__PURE__*/ React.createElement(ChartPopover, {
        ...props.calloutProps,
        XValue: calloutProps === null || calloutProps === void 0 ? void 0 : calloutProps.hoverXValue,
        yCalloutValue: calloutProps === null || calloutProps === void 0 ? void 0 : calloutProps.YValue,
        culture: props.culture,
        positioning: {
            target: refSelected
        },
        isPopoverOpen: isPopoverOpen,
        color: calloutProps === null || calloutProps === void 0 ? void 0 : calloutProps.color,
        isCartesian: false
    }), _renderLegends()) : /*#__PURE__*/ React.createElement("div", {
        id: _emptyChartId,
        role: 'alert',
        style: {
            opacity: '0'
        },
        "aria-label": 'Graph has no data to display'
    });
});
FunnelChart.displayName = 'FunnelChart';
