if (!window.blazorChart) {
    window.blazorChart = {};
}


window.blazorChart = {
    addDatasetData: (elementId, dataLabel, data) => {
        let chart = window.blazorChart.get(elementId);
        if (chart) {
            const chartData = chart.data;
            const chartDatasetData = data;

            if (!chartData.labels.includes(dataLabel))
                chartData.labels.push(dataLabel);

            const chartDatasets = chartData.datasets;

            if (chartDatasets.length > 0) {
                let datasetIndex = chartDatasets.findIndex(dataset => dataset.label === chartDatasetData.datasetLabel);
                if (datasetIndex > -1) {
                    chartDatasets[datasetIndex].data.push(chartDatasetData.data);
                    chart.update();
                }
            }
        }
    },
    addDatasetsData: (elementId, dataLabel, data) => {
        let chart = window.blazorChart.get(elementId);
        if (chart && data) {
            const chartData = chart.data;

            if (!chartData.labels.includes(dataLabel)) {
                chartData.labels.push(dataLabel);

                if (chartData.datasets.length > 0 && chartData.datasets.length === data.length) {
                    data.forEach(chartDatasetData => {
                        let datasetIndex = chartData.datasets.findIndex(dataset => dataset.label === chartDatasetData.datasetLabel);
                        chartData.datasets[datasetIndex].data.push(chartDatasetData.data);
                    });
                    chart.update();
                }
            }
        }
    },
    addDataset: (elementId, newDataset) => {
        let chart = window.blazorChart.get(elementId);
        if (chart) {
            chart.data.datasets.push(newDataset);
            chart.update();
        }
    },
    create: (elementId, type, data, options) => {
        let chartEl = document.getElementById(elementId);
        let _plugins = [];

        _plugins.push(ChartDataLabels);
        const config = {
            type: type,
            data: data,
            options: options,
            plugins: _plugins
        };

        if (type === 'line') {
            const tooltipLine = {
                id: 'tooltipLine',
                beforeDraw: chart => {
                    if (chart.tooltip?._active && chart.tooltip?._active.length) {
                        const ctx = chart.ctx;
                        ctx.save();
                        const activePoint = chart.tooltip._active[0];

                        ctx.beginPath();
                        ctx.setLineDash([5, 5]);
                        ctx.moveTo(activePoint.element.x, chart.chartArea.top);
                        ctx.lineTo(activePoint.element.x, activePoint.element.y);
                        ctx.linewidth = 2;
                        ctx.strokeStyle = 'grey';
                        ctx.stroke();
                        ctx.restore();

                        ctx.beginPath();
                        ctx.setLineDash([5, 5]);
                        ctx.moveTo(activePoint.element.x, activePoint.element.y);
                        ctx.lineTo(activePoint.element.x, chart.chartArea.bottom);
                        ctx.linewidth = 2;
                        ctx.strokeStyle = 'grey';
                        ctx.stroke();
                        ctx.restore();
                    }
                },
            };

            config.plugins.push(tooltipLine);
        }

        const chart = new Chart(
            chartEl,
            config
        );
    },
    get: (elementId) => {
        let chart;
        Chart.helpers.each(Chart.instances, function (instance) {
            if (instance.canvas.id === elementId) {
                chart = instance;
            }
        });

        return chart;
    },
    initialize: (elementId, type, data, options) => {
        let chart = window.blazorChart.get(elementId);
        if (chart) return;
        else
            window.blazorChart.create(elementId, type, data, options);
    },
    resize: (elementId, width, height) => {
        let chart = window.blazorChart.get(elementId);
        if (chart) {
            chart.canvas.parentNode.style.height = height;
            chart.canvas.parentNode.style.width = width;
        }
    },
    update: (elementId, data, options) => {
        let chart = window.blazorChart.get(elementId);
        if (chart) {
            chart.data = data;
            chart.options = options;
            chart.update();
        }
        else {
            console.warn(`The chart is not initialized. Initialize it and then call update.`);
        }
    },
    updateData: (elementId, data) => {
        let chart = window.blazorChart.get(elementId);
        if (chart) {
            window.blazorChart.mergeDatasets(chart.data.datasets, data.datasets);
            window.blazorChart.mergeLabels(chart.data, data);
            chart.update();
        }
    },
    mergeDatasets(oldDatasets, newDatasets) {
        for (let i = oldDatasets.length - 1; i >= 0; i--) {
            let sameDatasetInNewConfig = newDatasets.find(newD => newD.label === oldDatasets[i].label);
            if (sameDatasetInNewConfig === undefined) {
                oldDatasets.splice(i, 1);
            }
            else {
                oldDatasets[i].data = sameDatasetInNewConfig.data;
            }
        }
        let currentIds = oldDatasets.map(dataset => dataset.label);
        newDatasets.filter(newDataset => !currentIds.includes(newDataset.label)).forEach(newDataset => oldDatasets.push(newDataset));
    },
    mergeLabels(oldChartData, newChartData) {
        const innerFunc = (oldLabels, newLabels) => {
            if (newLabels == null || newLabels.length === 0) {
                if (oldLabels) {
                    oldLabels.length = 0;
                }
                return oldLabels;
            }
            if (oldLabels == null) {
                return newLabels;
            }
            oldLabels.length = 0;
            for (var i = 0; i < newLabels.length; i++) {
                oldLabels.push(newLabels[i]);
            }
            return oldLabels;
        };
        oldChartData.labels = innerFunc(oldChartData.labels, newChartData.labels);
    },
}