import { __assign } from "tslib";
/* eslint-disable @typescript-eslint/naming-convention */
import * as React from 'react';
import { useTheme } from '@fluentui/react';
import { DonutChart } from '../DonutChart/index';
import { VerticalStackedBarChart } from '../VerticalStackedBarChart/index';
import { decodeBase64Fields } from '@fluentui/chart-utilities';
import { isArrayOrTypedArray, isMonthArray, mapFluentChart, sanitizeJson } from '@fluentui/chart-utilities';
import { correctYearMonth, getGridProperties, isNonPlotType, transformPlotlyJsonToDonutProps, transformPlotlyJsonToVSBCProps, transformPlotlyJsonToAreaChartProps, transformPlotlyJsonToLineChartProps, transformPlotlyJsonToHorizontalBarWithAxisProps, transformPlotlyJsonToHeatmapProps, transformPlotlyJsonToSankeyProps, transformPlotlyJsonToGaugeProps, transformPlotlyJsonToGVBCProps, transformPlotlyJsonToVBCProps, transformPlotlyJsonToChartTableProps, transformPlotlyJsonToScatterChartProps, projectPolarToCartesian, getAllupLegendsProps, NON_PLOT_KEY_PREFIX, SINGLE_REPEAT, } from './PlotlySchemaAdapter';
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 { withResponsiveContainer } from '../ResponsiveContainer/withResponsiveContainer';
import { ScatterChart } from '../ScatterChart/index';
import { ChartTable } from '../ChartTable/index';
import { Legends } from '../Legends/index';
var ResponsiveDonutChart = withResponsiveContainer(DonutChart);
var ResponsiveVerticalStackedBarChart = withResponsiveContainer(VerticalStackedBarChart);
var ResponsiveLineChart = withResponsiveContainer(LineChart);
var ResponsiveHorizontalBarChartWithAxis = withResponsiveContainer(HorizontalBarChartWithAxis);
var ResponsiveAreaChart = withResponsiveContainer(AreaChart);
var ResponsiveHeatMapChart = withResponsiveContainer(HeatMapChart);
var ResponsiveSankeyChart = withResponsiveContainer(SankeyChart);
var ResponsiveGaugeChart = withResponsiveContainer(GaugeChart);
var ResponsiveGroupedVerticalBarChart = withResponsiveContainer(GroupedVerticalBarChart);
var ResponsiveVerticalBarChart = withResponsiveContainer(VerticalBarChart);
var ResponsiveScatterChart = withResponsiveContainer(ScatterChart);
var ResponsiveChartTable = withResponsiveContainer(ChartTable);
// Default x-axis key for grouping traces. Also applicable for PieData and SankeyData where x-axis is not defined.
var DEFAULT_XAXIS = 'x';
var FALLBACK_TYPE = 'fallback';
var useColorMapping = function () {
    var 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) {
    var chartProps = transformer.apply(void 0, transformerArgs);
    return (React.createElement("div", { key: "".concat(cellRow, "_").concat(cellColumn), style: {
            gridRowStart: cellRow,
            gridRowEnd: cellRow + 1,
            gridColumnStart: cellColumn,
            gridColumnEnd: cellColumn + 1,
        } },
        React.createElement(Renderer, __assign({}, chartProps, commonProps))));
}
var LineAreaPreTransformOp = function (plotlyInput) {
    var xValues = plotlyInput.data[0].x;
    var isXMonth = isMonthArray(xValues);
    var renderData = plotlyInput.data;
    if (isXMonth) {
        renderData = plotlyInput.data.map(function (dataPoint) { return (__assign(__assign({}, dataPoint), { x: correctYearMonth(dataPoint.x) })); });
    }
    return { data: renderData, layout: plotlyInput.layout };
};
var chartMap = {
    // 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,
    },
    fallback: {
        transformer: transformPlotlyJsonToVSBCProps,
        renderer: ResponsiveVerticalStackedBarChart,
    },
};
/**
 * DeclarativeChart component.
 * {@docCategory DeclarativeChart}
 */
export var DeclarativeChart = React.forwardRef(function (props, forwardedRef) {
    var _a;
    var plotlySchema = sanitizeJson(props.chartSchema).plotlySchema;
    var chart = mapFluentChart(plotlySchema);
    if (!chart.isValid) {
        throw new Error("Invalid chart schema: ".concat(chart.errorMessage));
    }
    var plotlyInput = plotlySchema;
    try {
        plotlyInput = decodeBase64Fields(plotlyInput);
    }
    catch (error) {
        throw new Error("Failed to decode plotly schema: ".concat(error));
    }
    var plotlyInputWithValidData = __assign(__assign({}, plotlyInput), { data: chart.validTracesInfo.map(function (trace) { return plotlyInput.data[trace.index]; }) });
    var validTracesFilteredIndex = chart.validTracesInfo.map(function (trace, index) { return ({
        index: index,
        type: trace.type,
    }); });
    var selectedLegends = plotlySchema.selectedLegends;
    var colorMap = useColorMapping();
    var theme = useTheme();
    var isDarkTheme = (_a = theme === null || theme === void 0 ? void 0 : theme.isInverted) !== null && _a !== void 0 ? _a : false;
    var chartRef = React.useRef(null);
    var isMultiPlot = React.useRef(false);
    if (!isArrayOrTypedArray(selectedLegends)) {
        selectedLegends = [];
    }
    var _b = React.useState(selectedLegends), activeLegends = _b[0], setActiveLegends = _b[1];
    var onActiveLegendsChange = function (keys) {
        setActiveLegends(keys);
        if (props.onSchemaChange) {
            props.onSchemaChange({ plotlySchema: { plotlyInput: plotlyInput, selectedLegends: keys } });
        }
    };
    React.useEffect(function () {
        // eslint-disable-next-line @typescript-eslint/no-shadow
        var plotlySchema = sanitizeJson(props.chartSchema).plotlySchema;
        // eslint-disable-next-line @typescript-eslint/no-shadow
        var selectedLegends = plotlySchema.selectedLegends;
        setActiveLegends(selectedLegends !== null && selectedLegends !== void 0 ? selectedLegends : []);
    }, [props.chartSchema]);
    var multiSelectLegendProps = {
        canSelectMultipleLegends: true,
        onChange: onActiveLegendsChange,
        selectedLegends: activeLegends,
    };
    var commonProps = {
        legendProps: multiSelectLegendProps,
        componentRef: chartRef,
        calloutProps: { layerProps: { eventBubblingEnabled: true } },
    };
    function createLegends(legendProps) {
        // eslint-disable-next-line react/jsx-no-bind
        return React.createElement(Legends, __assign({}, legendProps, { selectedLegends: activeLegends, onChange: onActiveLegendsChange }));
    }
    var exportAsImage = React.useCallback(function (opts) {
        return new Promise(function (resolve, reject) {
            if (isMultiPlot.current) {
                return reject(Error('Exporting multi plot charts as image is not supported'));
            }
            if (!chartRef.current || typeof chartRef.current.toImage !== 'function') {
                return reject(Error('Chart cannot be exported as image'));
            }
            chartRef.current
                .toImage(__assign({ background: theme.semanticColors.bodyBackground, scale: 5 }, opts))
                .then(resolve)
                .catch(reject);
        });
    }, [theme]);
    React.useImperativeHandle(props.componentRef, function () { return ({
        exportAsImage: exportAsImage,
    }); }, [exportAsImage]);
    if (chart.type === 'scatterpolar') {
        var cartesianProjection = projectPolarToCartesian(plotlyInputWithValidData);
        plotlyInputWithValidData.data = cartesianProjection.data;
        validTracesFilteredIndex.forEach(function (trace, index) {
            if (trace.type === 'scatterpolar') {
                validTracesFilteredIndex[index].type = 'line'; // Change type to line for rendering
            }
        });
    }
    var groupedTraces = {};
    var nonCartesianTraceCount = 0;
    plotlyInputWithValidData.data.forEach(function (trace, index) {
        var _a;
        var traceKey = '';
        if (isNonPlotType(chart.validTracesInfo[index].type)) {
            traceKey = "".concat(NON_PLOT_KEY_PREFIX).concat(nonCartesianTraceCount + 1);
            nonCartesianTraceCount++;
        }
        else {
            traceKey = (_a = trace.xaxis) !== null && _a !== void 0 ? _a : DEFAULT_XAXIS;
        }
        if (!groupedTraces[traceKey]) {
            groupedTraces[traceKey] = [];
        }
        groupedTraces[traceKey].push(index);
    });
    isMultiPlot.current = Object.keys(groupedTraces).length > 1;
    var gridProperties = getGridProperties(plotlyInputWithValidData, isMultiPlot.current, chart.validTracesInfo);
    // Render only one plot if the grid properties cannot determine positioning of multiple plots.
    if (isMultiPlot.current &&
        gridProperties.templateRows === SINGLE_REPEAT &&
        gridProperties.templateColumns === SINGLE_REPEAT) {
        Object.keys(groupedTraces).forEach(function (key, index) {
            if (index > 0) {
                delete groupedTraces[key];
            }
        });
        isMultiPlot.current = false;
    }
    var allupLegendsProps = getAllupLegendsProps(plotlyInputWithValidData, colorMap, props.colorwayType, chart.validTracesInfo, isDarkTheme);
    // map through the grouped traces and render the appropriate chart
    return (React.createElement(React.Fragment, null,
        React.createElement("div", { style: {
                display: 'grid',
                gridTemplateRows: gridProperties.templateRows,
                gridTemplateColumns: gridProperties.templateColumns,
            } }, Object.entries(groupedTraces).map(function (_a) {
            var _b, _c, _d;
            var xAxisKey = _a[0], index = _a[1];
            var plotlyInputForGroup = __assign(__assign({}, plotlyInputWithValidData), { data: index.map(function (idx) { return plotlyInputWithValidData.data[idx]; }) });
            var filteredTracesInfo = validTracesFilteredIndex.filter(function (trace) { return index.includes(trace.index); });
            var chartType = validTracesFilteredIndex.some(function (trace) { return trace.type === FALLBACK_TYPE; }) || chart.type === FALLBACK_TYPE
                ? FALLBACK_TYPE
                : filteredTracesInfo[0].type;
            if (validTracesFilteredIndex.some(function (trace) { return trace.type === 'line'; }) &&
                validTracesFilteredIndex.some(function (trace) { return trace.type === 'scatter'; })) {
                chartType = 'line';
            }
            var chartEntry = chartMap[chartType];
            if (chartEntry) {
                var transformer = chartEntry.transformer, renderer = chartEntry.renderer, preTransformCondition = chartEntry.preTransformCondition, preTransformOperation = chartEntry.preTransformOperation;
                if (preTransformCondition === undefined || preTransformCondition(plotlyInputForGroup)) {
                    var transformedInput = preTransformOperation
                        ? preTransformOperation(plotlyInputForGroup)
                        : plotlyInputForGroup;
                    var cellProperties = gridProperties.layout[xAxisKey];
                    return renderChart(renderer, transformer, [transformedInput, isMultiPlot.current, colorMap, props.colorwayType, isDarkTheme], __assign(__assign({}, commonProps), { xAxisAnnotation: cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.xAnnotation, yAxisAnnotation: cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.yAnnotation }), (_b = cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.row) !== null && _b !== void 0 ? _b : 1, (_c = cellProperties === null || cellProperties === void 0 ? void 0 : cellProperties.column) !== null && _c !== void 0 ? _c : 1);
                }
                return React.createElement(React.Fragment, null);
            }
            else {
                throw new Error("Unsupported chart type :".concat((_d = plotlyInputForGroup.data[0]) === null || _d === void 0 ? void 0 : _d.type));
            }
        })),
        isMultiPlot.current && createLegends(allupLegendsProps)));
});
DeclarativeChart.displayName = 'DeclarativeChart';
DeclarativeChart.defaultProps = {
    colorwayType: 'default',
};
//# sourceMappingURL=DeclarativeChart.js.map