/*
 * 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/>.
 */
let assignmentFreqChart;
let requestDistributionChart;

/**
 * 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 the assigment frequency chart with new incoming data, creates chart if it doesn't exist.
 *
 * @param canvas The canvas element to create/edit the chart on
 * @returns {(function(*))|*} A functinon that updates/creates the chart based on given data.
 */
function updateAssignmentFrequencyChart(canvas) {
    return data => {
        const assignmentNames = data.map(assignment => assignment["assignmentName"]);
        const assignmentSubmissionCounts = data.map(assignment => assignment["submissionCount"]);
        const assignmentQuestionCounts = data.map(assignment => assignment["questionCount"]);
        if (assignmentFreqChart) {
            assignmentFreqChart.data.labels = assignmentNames;
            assignmentFreqChart.data.datasets[0].data = assignmentSubmissionCounts;
            assignmentFreqChart.data.datasets[1].data = assignmentQuestionCounts;
            assignmentFreqChart.update();
        } else {
            assignmentFreqChart = new Chart(canvas, {
                type: "bar",
                data: {
                    labels: assignmentNames,
                    datasets: [
                        {
                            label: "Submission",
                            backgroundColor: getColorForPosition(1),
                            data: assignmentSubmissionCounts,
                            borderColor: "rgb(0,0,0)",
                            borderWidth: 1,
                        },
                        {
                            label: "Question",
                            backgroundColor: getColorForPosition(0),
                            data: assignmentQuestionCounts,
                            borderColor: "rgb(0,0,0)",
                            borderWidth: 1,
                        },
                    ],
                },
                options: {
                    plugins: {
                        legend: {
                            position: "bottom",
                        },
                    },
                    scales: {
                        x: {
                            stacked: true,
                            ticks: {
                                autoSkip: false,
                            },
                        },
                        y: {
                            stacked: true,
                            ticks: {
                                min: 0,
                                stepSize: 1,
                                beginAtZero: true,
                            },
                        },
                    },
                    animation: {
                        duration: 0,
                    },
                },
            });
        }
    };
}

/**
 * Updates the request distribution chart with new incoming data, creates chart if it doesn't exist.
 *
 * @param canvas The canvas to update
 * @returns {(function(*): void)|* } A function that updates the chart based on the given data.
 */
function updateRequestDistributionChart(canvas) {
    return data => {
        const courses = data.length ? [...new Set(data.map(dto => dto["requestsPerCourse"]).flatMap(obj => Object.keys(obj)))] : [];
        const bucketLabels = data.map(dto => dto["bucketLabel"]);
        const courseColors = {};
        for (const position in courses) {
            courseColors[courses[position]] = getColorForPosition(position);
        }

        const graphData = {
            labels: bucketLabels,
            datasets: courses.map(course => {
                const courseRequestFrequencies = data.map(dto => dto["requestsPerCourse"][course] || 0);
                return {
                    label: course,
                    data: courseRequestFrequencies,
                    backgroundColor: courseColors[course],
                    borderColor: "rgb(0,0,0)",
                    borderWidth: 1,
                };
            }),
        };

        if (requestDistributionChart) {
            requestDistributionChart.data = graphData;
            requestDistributionChart.update();
        } else {
            requestDistributionChart = new Chart(canvas, {
                type: "bar",
                data: graphData,
                options: {
                    plugins: {
                        legend: {
                            position: "bottom",
                        },
                    },
                    scales: {
                        y: {
                            stacked: true,
                            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 => {
        $(infoCards).find("#card-request-count").html(data["numRequests"]);
        $(infoCards).find("#card-submission-count").html(data["numSubmissions"]);
        $(infoCards).find("#card-question-count").html(data["numQuestions"]);
        $(infoCards).find("#card-enqueued-count").html(data["numEnqueued"]);
        $(infoCards)
            .find("#card-waiting-time")
            .html(msToHumanReadableTime(parseInt(data["avgWaitingTime"]) * 1000));
        $(infoCards)
            .find("#card-processing-time")
            .html(msToHumanReadableTime(parseInt(data["avgProcessingTime"]) * 1000));
    };
}
