'use client';
/* eslint-disable @typescript-eslint/naming-convention */ import * as React from 'react';
import { decodeBase64Fields, isArrayOrTypedArray, isMonthArray, mapFluentChart, sanitizeJson } from '@fluentui/chart-utilities';
import { tokens, typographyStyles } from '@fluentui/react-theme';
import { ThemeContext_unstable as V9ThemeContext } from '@fluentui/react-shared-contexts';
import { webLightTheme } from '@fluentui/tokens';
import * as d3Color from 'd3-color';
import { correctYearMonth, getGridProperties, isNonPlotType, transformPlotlyJsonToDonutProps, transformPlotlyJsonToVSBCProps, transformPlotlyJsonToAreaChartProps, transformPlotlyJsonToLineChartProps, transformPlotlyJsonToHorizontalBarWithAxisProps, transformPlotlyJsonToHeatmapProps, transformPlotlyJsonToSankeyProps, transformPlotlyJsonToGaugeProps, transformPlotlyJsonToGVBCProps, transformPlotlyJsonToVBCProps, transformPlotlyJsonToChartTableProps, transformPlotlyJsonToScatterChartProps, getAllupLegendsProps, NON_PLOT_KEY_PREFIX, SINGLE_REPEAT, transformPlotlyJsonToFunnelChartProps, transformPlotlyJsonToGanttChartProps, transformPlotlyJsonToAnnotationChartProps, transformPlotlyJsonToPolarChartProps, DEFAULT_POLAR_SUBPLOT } from './PlotlySchemaAdapter';
import { getChartTitleInlineStyles } from '../../utilities/index';
import { AnnotationOnlyChart } from '../AnnotationOnlyChart/AnnotationOnlyChart';
import { DonutChart } from '../DonutChart/index';
import { VerticalStackedBarChart } from '../VerticalStackedBarChart/index';
import { LineChart } from '../LineChart/index';
import { HorizontalBarChartWithAxis } from '../HorizontalBarChartWithAxis/index';
import { AreaChart } from '../AreaChart/index';
import { HeatMapChart } from '../HeatMapChart/index';
import { SankeyChart } from '../SankeyChart/SankeyChart';
import { GaugeChart } from '../GaugeChart/index';
import { GroupedVerticalBarChart } from '../GroupedVerticalBarChart/index';
import { VerticalBarChart } from '../VerticalBarChart/index';
import { ScatterChart } from '../ScatterChart/index';
import { FunnelChart } from '../FunnelChart/FunnelChart';
import { GanttChart } from '../GanttChart/index';
import { PolarChart } from '../PolarChart/index';
import { withResponsiveContainer } from '../ResponsiveContainer/withResponsiveContainer';
import { ChartTable } from '../ChartTable/index';
import { Legends } from '../Legends/index';
import { resolveCSSVariables, useRtl } from '../../utilities/index';
import { exportChartsAsImage } from '../../utilities/image-export-utils';
const ResponsiveDonutChart = withResponsiveContainer(DonutChart);
const ResponsiveVerticalStackedBarChart = withResponsiveContainer(VerticalStackedBarChart);
const ResponsiveLineChart = withResponsiveContainer(LineChart);
const ResponsiveHorizontalBarChartWithAxis = withResponsiveContainer(HorizontalBarChartWithAxis);
const ResponsiveAreaChart = withResponsiveContainer(AreaChart);
const ResponsiveHeatMapChart = withResponsiveContainer(HeatMapChart);
const ResponsiveSankeyChart = withResponsiveContainer(SankeyChart);
const ResponsiveGaugeChart = withResponsiveContainer(GaugeChart);
const ResponsiveGroupedVerticalBarChart = withResponsiveContainer(GroupedVerticalBarChart);
const ResponsiveVerticalBarChart = withResponsiveContainer(VerticalBarChart);
const ResponsiveScatterChart = withResponsiveContainer(ScatterChart);
const ResponsiveChartTable = withResponsiveContainer(ChartTable);
const ResponsiveGanttChart = withResponsiveContainer(GanttChart);
// Removing responsive wrapper for FunnelChart as responsive container is not working with FunnelChart
//const ResponsiveFunnelChart = withResponsiveContainer(FunnelChart);
const ResponsivePolarChart = withResponsiveContainer(PolarChart);
// Default x-axis key for grouping traces. Also applicable for PieData and SankeyData where x-axis is not defined.
const DEFAULT_XAXIS = 'x';
const useColorMapping = ()=>{
    const colorMap = React.useRef(new Map());
    return colorMap;
};
function renderChart(Renderer, // eslint-disable-next-line @typescript-eslint/no-explicit-any
transformer, // eslint-disable-next-line @typescript-eslint/no-explicit-any
transformerArgs, commonProps, cellRow, cellColumn) {
    const chartProps = transformer(...transformerArgs);
    return /*#__PURE__*/ React.createElement("div", {
        key: `${cellRow}_${cellColumn}`,
        style: {
            gridRowStart: cellRow,
            gridRowEnd: cellRow + 1,
            gridColumnStart: cellColumn,
            gridColumnEnd: cellColumn + 1
        }
    }, /*#__PURE__*/ React.createElement(Renderer, {
        ...chartProps,
        ...commonProps
    }));
}
const LineAreaPreTransformOp = (plotlyInput)=>{
    const xValues = plotlyInput.data[0].x;
    const isXMonth = isMonthArray(xValues);
    let renderData = plotlyInput.data;
    if (isXMonth) {
        renderData = plotlyInput.data.map((dataPoint)=>({
                ...dataPoint,
                x: correctYearMonth(dataPoint.x)
            }));
    }
    return {
        data: renderData,
        layout: plotlyInput.layout
    };
};
const chartMap = {
    annotation: {
        transformer: transformPlotlyJsonToAnnotationChartProps,
        renderer: AnnotationOnlyChart
    },
    // PieData category charts
    donut: {
        transformer: transformPlotlyJsonToDonutProps,
        renderer: ResponsiveDonutChart
    },
    // SankeyData category charts
    sankey: {
        transformer: transformPlotlyJsonToSankeyProps,
        renderer: ResponsiveSankeyChart
    },
    // TableData category charts
    table: {
        transformer: transformPlotlyJsonToChartTableProps,
        renderer: ResponsiveChartTable
    },
    // PlotData category charts
    horizontalbar: {
        transformer: transformPlotlyJsonToHorizontalBarWithAxisProps,
        renderer: ResponsiveHorizontalBarChartWithAxis
    },
    groupedverticalbar: {
        transformer: transformPlotlyJsonToGVBCProps,
        renderer: ResponsiveGroupedVerticalBarChart
    },
    verticalstackedbar: {
        transformer: transformPlotlyJsonToVSBCProps,
        renderer: ResponsiveVerticalStackedBarChart
    },
    heatmap: {
        transformer: transformPlotlyJsonToHeatmapProps,
        renderer: ResponsiveHeatMapChart
    },
    gauge: {
        transformer: transformPlotlyJsonToGaugeProps,
        renderer: ResponsiveGaugeChart
    },
    verticalbar: {
        transformer: transformPlotlyJsonToVBCProps,
        renderer: ResponsiveVerticalBarChart
    },
    area: {
        transformer: transformPlotlyJsonToAreaChartProps,
        renderer: ResponsiveAreaChart,
        preTransformOperation: LineAreaPreTransformOp
    },
    line: {
        transformer: transformPlotlyJsonToLineChartProps,
        renderer: ResponsiveLineChart,
        preTransformOperation: LineAreaPreTransformOp
    },
    scatter: {
        transformer: transformPlotlyJsonToScatterChartProps,
        renderer: ResponsiveScatterChart,
        preTransformOperation: LineAreaPreTransformOp
    },
    gantt: {
        transformer: transformPlotlyJsonToGanttChartProps,
        renderer: ResponsiveGanttChart
    },
    funnel: {
        transformer: transformPlotlyJsonToFunnelChartProps,
        renderer: FunnelChart
    },
    scatterpolar: {
        transformer: transformPlotlyJsonToPolarChartProps,
        renderer: ResponsivePolarChart
    },
    fallback: {
        transformer: transformPlotlyJsonToVSBCProps,
        renderer: ResponsiveVerticalStackedBarChart
    }
};
const useIsDarkTheme = ()=>{
    const parentV9Theme = React.useContext(V9ThemeContext);
    const v9Theme = parentV9Theme ? parentV9Theme : webLightTheme;
    // Get background and foreground colors
    const backgroundColor = d3Color.hsl(v9Theme.colorNeutralBackground1);
    const foregroundColor = d3Color.hsl(v9Theme.colorNeutralForeground1);
    const isDarkTheme = backgroundColor.l < foregroundColor.l;
    return isDarkTheme;
};
/**
 * DeclarativeChart component.
 * {@docCategory DeclarativeChart}
 */ export const DeclarativeChart = /*#__PURE__*/ React.forwardRef(({ colorwayType = 'default', ...props }, forwardedRef)=>{
    var _plotlyInputWithValidData_layout;
    const { plotlySchema } = sanitizeJson(props.chartSchema);
    const chart = mapFluentChart(plotlySchema);
    if (!chart.isValid) {
        throw new Error(`Invalid chart schema: ${chart.errorMessage}`);
    }
    let plotlyInput = plotlySchema;
    try {
        plotlyInput = decodeBase64Fields(plotlyInput);
    } catch (error) {
        throw new Error(`Failed to decode plotly schema: ${error}`);
    }
    const plotlyInputWithValidData = {
        ...plotlyInput,
        data: chart.validTracesInfo.map((trace)=>plotlyInput.data[trace.index])
    };
    const validTracesFilteredIndex = chart.validTracesInfo.map((trace, index)=>({
            index,
            type: trace.type
        }));
    let { selectedLegends } = plotlySchema;
    const colorMap = useColorMapping();
    const isDarkTheme = useIsDarkTheme();
    const chartRefs = React.useRef([]);
    const isMultiPlot = React.useRef(false);
    const legendsRef = React.useRef(null);
    const containerRef = React.useRef(null);
    const isRTL = useRtl();
    if (!isArrayOrTypedArray(selectedLegends)) {
        selectedLegends = [];
    }
    const [activeLegends, setActiveLegends] = React.useState(selectedLegends);
    const onActiveLegendsChange = (keys)=>{
        setActiveLegends(keys);
        if (props.onSchemaChange) {
            props.onSchemaChange({
                plotlySchema: {
                    plotlyInput,
                    selectedLegends: keys
                }
            });
        }
    };
    React.useEffect(()=>{
        // eslint-disable-next-line @typescript-eslint/no-shadow
        const { plotlySchema } = sanitizeJson(props.chartSchema);
        // eslint-disable-next-line @typescript-eslint/no-shadow
        const { selectedLegends } = plotlySchema;
        // eslint-disable-next-line react-hooks/set-state-in-effect
        setActiveLegends(selectedLegends !== null && selectedLegends !== void 0 ? selectedLegends : []);
    }, [
        props.chartSchema
    ]);
    const multiSelectLegendProps = {
        canSelectMultipleLegends: true,
        onChange: onActiveLegendsChange,
        selectedLegends: activeLegends
    };
    const interactiveCommonProps = {
        legendProps: multiSelectLegendProps
    };
    function createLegends(legendProps) {
        return /*#__PURE__*/ React.createElement(Legends, {
            ...legendProps,
            selectedLegends: activeLegends,
            onChange: onActiveLegendsChange,
            legendRef: legendsRef
        });
    }
    const exportAsImage = React.useCallback(async (opts)=>{
        var _legendsRef_current;
        if (!containerRef.current) {
            throw new Error('Container reference is null');
        }
        const imgExpOpts = {
            background: resolveCSSVariables(containerRef.current, tokens.colorNeutralBackground1),
            scale: 5,
            ...opts
        };
        if (!isMultiPlot.current) {
            var _chartRefs_current__compRef, _chartRefs_current_;
            if (!((_chartRefs_current_ = chartRefs.current[0]) === null || _chartRefs_current_ === void 0 ? void 0 : (_chartRefs_current__compRef = _chartRefs_current_.compRef) === null || _chartRefs_current__compRef === void 0 ? void 0 : _chartRefs_current__compRef.toImage)) {
                throw new Error('Chart cannot be exported as image');
            }
            return chartRefs.current[0].compRef.toImage(imgExpOpts);
        }
        return exportChartsAsImage(chartRefs.current.map((item)=>{
            var _item_compRef;
            return {
                container: (_item_compRef = item.compRef) === null || _item_compRef === void 0 ? void 0 : _item_compRef.chartContainer,
                row: item.row,
                col: item.col
            };
        }), (_legendsRef_current = legendsRef.current) === null || _legendsRef_current === void 0 ? void 0 : _legendsRef_current.toSVG, isRTL, imgExpOpts);
    }, [
        isRTL
    ]);
    React.useImperativeHandle(props.componentRef, ()=>({
            exportAsImage
        }), [
        exportAsImage
    ]);
    const groupedTraces = {};
    let nonCartesianTraceCount = 0;
    // For annotation-only charts, create a single group entry
    if (chart.type === 'annotation') {
        groupedTraces[DEFAULT_XAXIS] = [];
    } else {
        plotlyInputWithValidData.data.forEach((trace, index)=>{
            let traceKey = '';
            if (isNonPlotType(chart.validTracesInfo[index].type)) {
                traceKey = `${NON_PLOT_KEY_PREFIX}${nonCartesianTraceCount + 1}`;
                nonCartesianTraceCount++;
            } else {
                var _trace_subplot, _trace_xaxis;
                traceKey = chart.validTracesInfo[index].type === 'scatterpolar' ? (_trace_subplot = trace.subplot) !== null && _trace_subplot !== void 0 ? _trace_subplot : DEFAULT_POLAR_SUBPLOT : (_trace_xaxis = trace.xaxis) !== null && _trace_xaxis !== void 0 ? _trace_xaxis : DEFAULT_XAXIS;
            }
            if (!groupedTraces[traceKey]) {
                groupedTraces[traceKey] = [];
            }
            groupedTraces[traceKey].push(index);
        });
    }
    // eslint-disable-next-line react-hooks/refs
    isMultiPlot.current = Object.keys(groupedTraces).length > 1;
    const gridProperties = getGridProperties(plotlyInputWithValidData, // eslint-disable-next-line react-hooks/refs
    isMultiPlot.current, chart.validTracesInfo);
    // Render only one plot if the grid properties cannot determine positioning of multiple plots.
    if (// eslint-disable-next-line react-hooks/refs
    isMultiPlot.current && gridProperties.templateRows === SINGLE_REPEAT && gridProperties.templateColumns === SINGLE_REPEAT) {
        if (chart.type === 'donut') {
            // If there are multiple data traces for donut/pie, picking the last one similar to plotly
            const keys = Object.keys(groupedTraces);
            keys.forEach((key, index)=>{
                if (index < keys.length - 1) {
                    delete groupedTraces[key];
                }
            });
        } else {
            Object.keys(groupedTraces).forEach((key, index)=>{
                if (index > 0) {
                    delete groupedTraces[key];
                }
            });
        }
        // eslint-disable-next-line react-hooks/refs
        isMultiPlot.current = false;
    }
    const allupLegendsProps = getAllupLegendsProps(plotlyInputWithValidData, colorMap, colorwayType, chart.validTracesInfo, isDarkTheme);
    const titleObj = (_plotlyInputWithValidData_layout = plotlyInputWithValidData.layout) === null || _plotlyInputWithValidData_layout === void 0 ? void 0 : _plotlyInputWithValidData_layout.title;
    var _titleObj_text;
    const chartTitle = typeof titleObj === 'string' ? titleObj : (_titleObj_text = titleObj === null || titleObj === void 0 ? void 0 : titleObj.text) !== null && _titleObj_text !== void 0 ? _titleObj_text : '';
    const titleFont = typeof titleObj === 'object' ? titleObj === null || titleObj === void 0 ? void 0 : titleObj.font : undefined;
    const titleStyle = {
        ...typographyStyles.caption1,
        color: tokens.colorNeutralForeground1,
        textAlign: 'center',
        marginBottom: tokens.spacingVerticalS,
        ...getChartTitleInlineStyles(titleFont)
    };
    // map through the grouped traces and render the appropriate chart
    return /*#__PURE__*/ React.createElement(React.Fragment, null, isMultiPlot.current && chartTitle && /*#__PURE__*/ React.createElement("div", {
        style: titleStyle
    }, chartTitle), /*#__PURE__*/ React.createElement("div", {
        style: {
            display: 'grid',
            gridTemplateRows: gridProperties.templateRows,
            gridTemplateColumns: gridProperties.templateColumns
        },
        ref: containerRef
    }, Object.entries(groupedTraces).map(([xAxisKey, index], chartIdx)=>{
        var _filteredTracesInfo_;
        const plotlyInputForGroup = {
            ...plotlyInputWithValidData,
            data: index.map((idx)=>plotlyInputWithValidData.data[idx])
        };
        const filteredTracesInfo = validTracesFilteredIndex.filter((trace)=>index.includes(trace.index));
        var _filteredTracesInfo__type;
        let chartType = chart.type === 'fallback' || chart.type === 'groupedverticalbar' ? chart.type : (_filteredTracesInfo__type = (_filteredTracesInfo_ = filteredTracesInfo[0]) === null || _filteredTracesInfo_ === void 0 ? void 0 : _filteredTracesInfo_.type) !== null && _filteredTracesInfo__type !== void 0 ? _filteredTracesInfo__type : chart.type;
        if (validTracesFilteredIndex.some((trace)=>trace.type === 'line') && validTracesFilteredIndex.some((trace)=>trace.type === 'scatter')) {
            chartType = 'line';
        }
        const chartEntry = chartMap[chartType];
        if (chartEntry) {
            const { transformer, renderer, preTransformCondition, preTransformOperation } = chartEntry;
            if (preTransformCondition === undefined || preTransformCondition(plotlyInputForGroup)) {
                const transformedInput = preTransformOperation ? preTransformOperation(plotlyInputForGroup) : plotlyInputForGroup;
                const cellProperties = gridProperties.layout[xAxisKey];
                const resolvedCommonProps = chartType === 'annotation' ? {} : {
                    ...interactiveCommonProps
                };
                var _cellProperties_row, _cellProperties_column;
                return renderChart(renderer, transformer, [
                    transformedInput,
                    isMultiPlot.current,
                    colorMap,
                    colorwayType,
                    isDarkTheme
                ], {
                    ...resolvedCommonProps,
                    ...(cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.xAnnotation) && {
                        xAxisAnnotation: cellProperties.xAnnotation
                    },
                    ...(cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.yAnnotation) && {
                        yAxisAnnotation: cellProperties.yAnnotation
                    },
                    componentRef: (ref)=>{
                        var _cellProperties_row, _cellProperties_column;
                        chartRefs.current[chartIdx] = {
                            compRef: ref,
                            row: (_cellProperties_row = cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.row) !== null && _cellProperties_row !== void 0 ? _cellProperties_row : 1,
                            col: (_cellProperties_column = cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.column) !== null && _cellProperties_column !== void 0 ? _cellProperties_column : 1
                        };
                    }
                }, (_cellProperties_row = cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.row) !== null && _cellProperties_row !== void 0 ? _cellProperties_row : 1, (_cellProperties_column = cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.column) !== null && _cellProperties_column !== void 0 ? _cellProperties_column : 1);
            }
            return /*#__PURE__*/ React.createElement(React.Fragment, null);
        } else {
            var _plotlyInputForGroup_data_;
            throw new Error(`Unsupported chart type :${(_plotlyInputForGroup_data_ = plotlyInputForGroup.data[0]) === null || _plotlyInputForGroup_data_ === void 0 ? void 0 : _plotlyInputForGroup_data_.type}`);
        }
    })), isMultiPlot.current && createLegends(allupLegendsProps));
});
DeclarativeChart.displayName = 'DeclarativeChart';
