<script setup lang="ts">
import type { ChartDataset, ChartOptions, ChartType } from 'chart.js';

const COLOURS = [
    '#C71585',
    '#dc3545',
    '#fd7e14',
    '#ffc107',
    '#198754',
    '#20c997',
    '#0dcaf0',
    '#0d6efd',
    '#6610f2',
    '#6f42c1',
    '#d63384',
];

export type Dataset = Record<number | string, number>;

const props = withDefaults(defineProps<{
    label: string;
    data: Dataset[] | Dataset;
    cumulative?: boolean;
    type?: ChartType;
    options?: ChartOptions;
}>(), {
    type: 'line',
    options: () => ({
        responsive: true,
        interaction: {
            intersect: false,
            mode: 'index',
        },
    }),
});

onMounted(async () => {
    await drawChart();
});

const buildDataset = (data: Dataset, label: string, colour: string): ChartDataset => {
    return {
        label,
        data: props.cumulative
            ? accumulate(Object.values(data))
            : Object.values(data),
        fill: false,
        backgroundColor: colour,
        borderColor: colour,
    };
};
const isMultiDataset = (data: Dataset[] | Dataset): data is Dataset[] => {
    return Object.values(data).length > 0 && typeof Object.values(data)[0] === 'object';
};

const canvas = useTemplateRef<HTMLCanvasElement>('canvas');
const drawChart = async () => {
    if (!canvas.value) {
        throw new Error('cannot find canvas');
    }

    let colourIndex = 0;
    const { default: Chart } = await import('chart.js/auto');
    new Chart(canvas.value, {
        type: props.type,
        data: {
            labels: isMultiDataset(props.data)
                ? Array.from(Object.values(props.data).reduce((carry, item) => {
                        for (const key in item) {
                            carry.add(key);
                        }
                        return carry;
                    }, new Set()))
                : Object.keys(props.data),
            datasets: isMultiDataset(props.data)
                ? Object.entries(props.data).map(([key, data]) => buildDataset(data, key, COLOURS[colourIndex++ % COLOURS.length]))
                : [buildDataset(props.data, props.label, COLOURS[0])],
        },
        options: props.options,
    });
};

const accumulate = (values: number[]): number[] => {
    const newValues = [];
    let acc = 0;
    for (const v of values) {
        acc += v;
        newValues.push(acc);
    }
    return newValues;
};
</script>

<template>
    <canvas ref="canvas"></canvas>
</template>
