/*
 * Queue - A Queueing system that can be used to handle labs in higher education
 * Copyright (C) 2016-2024  Delft University of Technology
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

/**
 * Deletes all previous data and refreshes the table based on new data.
 * The latest request interactions are shown at the top of the table.
 *
 * @param table The assistant frequency table to modify.
 * @returns {(function(*): void)|*} A function that will take the data and update the table.
 */
function updateAssistantFrequencyTable(table) {
    return data => {
        $(table).find("tbody").children().remove();

        const assistantNames = data["assistantNames"];
        const requestsPerAssistant = data["requestsPerAssistant"];
        const timeSinceLastRequestInteraction = data["timeSinceLastRequestInteraction"];

        Object.keys(assistantNames)
            .sort()
            .forEach(assistantId => {
                const assistantName = assistantNames[assistantId];
                const numRequestsTaken = requestsPerAssistant[assistantId] || 0;
                const lastInteraction = timeSinceLastRequestInteraction[assistantId]
                    ? msToHumanReadableTime(timeSinceLastRequestInteraction[assistantId])
                    : "No Activity";

                $(table)
                    .find("tbody")
                    .append("<tr><td>" + assistantName + "</td><td>" + numRequestsTaken + "</td><td>" + lastInteraction + "</td></tr>");
            });
    };
}

/**
 * Updates or creates a distribution chart (request, building, etc) with new incoming data.
 *
 * @param canvas The canvas to update
 * @param chartName The name of the chart
 * @param chartType The type of chart
 * @param stacked Whether to stack y-axis values (e.g. stacked bar chart)
 * @param yAxisLabel The label of the y-axis
 * @returns {(function(*): void)|*} A function which updates the chart accordingly.
 */
function updateDistributionChart(canvas, chartName, chartType, stacked, yAxisLabel = null) {
    return data => {
        // groups corresponds to concepts such as editions or buildings
        const groups = data.length ? [...new Set(data.map(dto => dto["bucketData"]).flatMap(obj => Object.keys(obj)))] : [];
        // bucket labels corresponds to discretised units of the x-axis (timestamps)
        const bucketLabels = data.map(dto => dto["bucketLabel"]);
        const groupColors = {};
        for (const position in groups) {
            groupColors[groups[position]] = getArbitraryColorForGraph(position);
        }

        const graphData = {
            labels: bucketLabels,
            datasets: groups.map(group => {
                const groupFrequencies = data.map(dto => dto["bucketData"][group] || 0);
                return {
                    label: group,
                    data: groupFrequencies,
                    backgroundColor: groupColors[group],
                    borderColor: chartType === "bar" ? getBorderColor() : groupColors[group],
                    borderWidth: chartType === "bar" ? 1 : 3,
                };
            }),
        };

        if (window[chartName]) {
            window[chartName].data = graphData;
            window[chartName].update();
        } else {
            window[chartName] = new Chart(canvas, {
                type: chartType, // "bar", "line"
                data: graphData,
                options: {
                    plugins: {
                        legend: {
                            position: "bottom",
                        },
                    },
                    scales: {
                        y: {
                            title: {
                                text: yAxisLabel,
                                display: yAxisLabel !== null,
                            },
                            stacked: stacked,
                            ticks: {
                                min: 0,
                                stepSize: 1,
                                beginAtZero: true,
                            },
                        },
                        x: {
                            stacked: true,
                            ticks: {
                                autoSkip: false,
                                maxRotation: 80,
                            },
                        },
                    },
                    animation: {
                        duration: 0,
                    },
                },
            });
        }
    };
}

/**
 * Updates the general information inside the statistic cards
 * @param infoCards The infoCards div containing all the stat cards
 * @returns {(function(*))|*} A function that will take the data and update the cards.
 */
function updateGeneralInformation(infoCards) {
    return data => {
        const numQuestions = parseInt(data["requestCounts"]["questionCount"]);
        const numSubmissions = parseInt(data["requestCounts"]["submissionCount"]);
        $(infoCards)
            .find("#card-request-count")
            .html(numQuestions + numSubmissions);
        $(infoCards).find("#card-question-count").html(numQuestions);
        $(infoCards).find("#card-submission-count").html(numSubmissions);
        $(infoCards).find("#card-enqueued-count").html(data["numEnqueued"]);
        $(infoCards)
            .find("#card-waiting-time")
            .html(msToHumanReadableTime(parseInt(data["avgWaitingTime"])));
        $(infoCards)
            .find("#card-processing-time")
            .html(msToHumanReadableTime(parseInt(data["avgProcessingTime"])));
    };
}
