/******************************************************************************
 * Copyright (c) 2024, 2026 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the terms
 * of the MIT License which is available at https://opensource.org/licenses/MIT
 *
 * SPDX-License-Identifier: MIT
 *****************************************************************************/

function buildQuizzes() {
    // Replace contents of HTML elements using the 'quiz' class with a dynamically generated quiz.
    const quizzes = document.getElementsByClassName('quiz');
    for (let i = 0; i < quizzes.length; i++) {
        buildQuiz(quizzes[i], 'quiz' + i);
    }
}

function buildQuiz(quizElement, quizId) {
    // Get quiz questions and answers from the JSON data in the HTML element's body.
    let questions = eval(quizElement.innerHTML);

    // Clear the HTML element's body, such that we can add new HTML elements for the quiz questions and answers.
    quizElement.innerHTML = '';

    // Generate HTML elements for the 'show solution' modal dialog.
    const modalWrapDiv = document.createElement('div');
    modalWrapDiv.classList.add('modal-wrap');
    quizElement.appendChild(modalWrapDiv);
    modalWrapDiv.innerHTML =
        `<div id="${quizId}-modal" class="modal fade" tabindex="-1" aria-labelledby="${quizId}-modal-title" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="${quizId}-modal-title">(to be filled in by JavaScript code)</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <p>Are you sure you want to show the solution to this quiz question?</p>
                        <p>
                            It is recommended to first try the quiz yourself.
                            And if you get a question wrong, it is recommended to read the page again, think a bit more, and then retry the question.
                            This way, you learn more than by directly showing the solution.
                        </p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn escet-btn" data-bs-dismiss="modal" id="${quizId}-show-solution">Show solution</button>
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                    </div>
                </div>
            </div>
        </div>`;

    // Generate HTML elements for questions and answers.
    const output = [];
    questions.forEach((currentQuestion, questionNumber) => {
        const answers = [];
        for (let i = 0; i < currentQuestion.answers.length; i++) {
            let answer = currentQuestion.answers[i];
            if (currentQuestion.type === 'single-choice') {
                // Create radio inputs for single-choice question.
                answers.push(
                    `<div class="quiz-answer">
                        <div><input type='radio' name='${quizId}-question${questionNumber}' id='${quizId}-question${questionNumber}-${i + 1}' value='${i + 1}'></div>
                        <label for='${quizId}-question${questionNumber}-${i + 1}'>${answer}</label>
                    </div>`
                );
            } else if (currentQuestion.type === 'multiple-choice') {
                // Create checkboxes for multiple-choice question.
                answers.push(
                    `<div class="quiz-answer">
                        <div><input type='checkbox' name='${quizId}-question${questionNumber}' id='${quizId}-question${questionNumber}-${i + 1}' value='${i + 1}'></div>
                        <label for='${quizId}-question${questionNumber}-${i + 1}'>${answer}</label>
                    </div>`
                );
            } else {
                console.error('Unknown question type: ' + currentQuestion.type);
            }
        }

        // Add this question and its answers to the output.
        output.push(
            `<div id='${quizId}-question${questionNumber}' class='quiz-question-wrap'>
                 <div class='quiz-question'>${questionNumber + 1}. ${currentQuestion.question}</div>
                 <div class='quiz-answers'>${answers.join('')}</div>
                 <div class='quiz-question-feedback clearfix'>
                     <div class='quiz-question-correctness float-start'></div>
                     <button id='${quizId}-question${questionNumber}-show-solution-button' class='quiz-question-show-solution btn btn-sm btn-outline-secondary float-end' data-bs-toggle='modal' data-bs-target='#${quizId}-modal' data-escet-question-number='${questionNumber}'>Show solution</button>
                 </div>
             </div>`
        );
    });

    // Fill the HTML placeholder element with our generated HTML, and a submit button, and a placeholder for the quiz
    // feedback.
    const quizDiv = document.createElement('div');
    quizDiv.classList.add('quiz-questions-wrap');
    quizElement.appendChild(quizDiv);

    const submitButton = document.createElement('button');
    submitButton.textContent = 'Check answers';
    submitButton.classList.add('submit');
    submitButton.classList.add('btn');
    submitButton.classList.add('escet-btn');
    quizElement.appendChild(submitButton);

    const quizFeedbackDiv = document.createElement('div');
    quizFeedbackDiv.classList.add('quiz-feedback');
    quizElement.appendChild(quizFeedbackDiv);

    quizDiv.innerHTML = output.join('');

    // Mark the quiz as having been built.
    quizElement.classList.add('quiz-built');

    // Add click event listener for the submit button, to check answers and provide feedback.
    submitButton.addEventListener('click', () => {
        // Get the answers provided by the user.
        const answerContainers = quizDiv.querySelectorAll('.quiz-answers');
        const questionCorrectnessDivs = quizDiv.querySelectorAll('.quiz-question-correctness');

        // Track the number of answered questions and correctly-answered questions.
        let numAnswered = 0;
        let numCorrect = 0;

        // Find the provided answer(s) for each question and check it/them against the correct answer(s).
        questions.forEach((currentQuestion, questionNumber) => {
            // Find the selected answer(s).
            const answerContainer = answerContainers[questionNumber];
            const questionCorrectnessDiv = questionCorrectnessDivs[questionNumber];
            const selector = `input[name=${quizId}-question${questionNumber}]:checked`;
            let userAnswer;
            if (currentQuestion.type === 'single-choice') {
                // Single-choice question.
                userAnswer = (answerContainer.querySelector(selector) || {}).value;
            } else if (currentQuestion.type === 'multiple-choice') {
                // Multiple-choice question.
                userAnswer = Array.from(answerContainer.querySelectorAll(selector)).map(x => x.value).join(', ');
            } else {
                console.error('Unknown question type: ' + currentQuestion.type);
            }

            if (typeof userAnswer === 'undefined') {
                // The single-choice question is not answered. Provide feedback on the unanswered question.
                answerContainer.classList.remove('quiz-correct-answer');
                answerContainer.classList.add('quiz-incorrect-answer');
                questionCorrectnessDiv.classList.remove('quiz-correct-answer');
                questionCorrectnessDiv.classList.add('quiz-incorrect-answer');
                questionCorrectnessDiv.innerHTML = 'No answer is given.';
            } else if (userAnswer === currentQuestion.correctAnswer) {
                // The question is answered correctly.
                numAnswered++;
                numCorrect++;

                // Provide feedback on the correctly answered question.
                answerContainer.classList.remove('quiz-incorrect-answer');
                answerContainer.classList.add('quiz-correct-answer');
                questionCorrectnessDiv.classList.remove('quiz-incorrect-answer');
                questionCorrectnessDiv.classList.add('quiz-correct-answer');
                questionCorrectnessDiv.innerHTML = 'The answer is correct.';
            } else {
                // The question is answered, but incorrectly.
                numAnswered++;

                // Provide feedback on the incorrectly answered question.
                answerContainer.classList.remove('quiz-correct-answer');
                answerContainer.classList.add('quiz-incorrect-answer');
                questionCorrectnessDiv.classList.remove('quiz-correct-answer');
                questionCorrectnessDiv.classList.add('quiz-incorrect-answer');
                questionCorrectnessDiv.innerHTML = 'The answer is incorrect.';
            }
        });

        // Provide feedback on the entire quiz.
        const numUnanswered = questions.length - numAnswered;

        if (numUnanswered > 0) {
            quizFeedbackDiv.classList.remove('quiz-correct-answer');
            quizFeedbackDiv.classList.add('quiz-incorrect-answer');
            feedback = `For ${numUnanswered} question${numUnanswered > 1 ? 's' : ''}, you did not yet give an answer.`;
            feedback += ' Answer all questions and check your answers again.';
        } else {
            feedback = `You answered ${numCorrect} out of ${questions.length} question${questions.length > 1 ? 's' : ''} correctly.`;
            if (numCorrect === questions.length) {
                quizFeedbackDiv.classList.remove('quiz-incorrect-answer');
                quizFeedbackDiv.classList.add('quiz-correct-answer');
                feedback += ' Please proceed!';
            } else {
                quizFeedbackDiv.classList.remove('quiz-correct-answer');
                quizFeedbackDiv.classList.add('quiz-incorrect-answer');
                feedback += ' Please study the previous section again and then try the quiz once more.';
            }
        }
        quizFeedbackDiv.innerHTML = feedback;
        resetAnimation(quizFeedbackDiv);
    });

    // Add change event listeners for the radio/check buttons, to invalidate outdated quiz feedback.
    const answerContainers = quizDiv.querySelectorAll('.quiz-answers');
    const questionCorrectnessDivs = quizDiv.querySelectorAll('.quiz-question-correctness');
    questions.forEach((currentQuestion, questionNumber) => {
        const questionAnswerContainer = answerContainers[questionNumber];
        const questionButtons = questionAnswerContainer.querySelectorAll('input');
        const questionCorrectnessDiv = questionCorrectnessDivs[questionNumber];
        questionButtons.forEach(questionButton => {
            questionButton.addEventListener('change', function() {
                // Invalidate outdated question feedback.
                questionAnswerContainer.classList.remove('quiz-incorrect-answer');
                questionAnswerContainer.classList.remove('quiz-correct-answer');
                questionCorrectnessDiv.classList.remove('quiz-incorrect-answer');
                questionCorrectnessDiv.classList.remove('quiz-correct-answer');
                questionCorrectnessDiv.innerHTML = '';

                // Invalidate outdated quiz feedback.
                quizFeedbackDiv.classList.remove('quiz-incorrect-answer');
                quizFeedbackDiv.classList.remove('quiz-correct-answer');
                quizFeedbackDiv.innerHTML = '';
            });
        });
    });

    // Add 'show modal dialog' event listener, to connect it to the specific question.
    const quizModalElem = document.querySelector(`#${quizId}-modal`);
    quizModalElem.addEventListener('show.bs.modal', function(event) {
        // Set the dialog title.
        const button = event.relatedTarget;
        const questionNumber = Number(button.getAttribute('data-escet-question-number'));
        var modalTitle = quizModalElem.querySelector(`#${quizId}-modal-title`);
        modalTitle.textContent = `Show solution to quiz question ${questionNumber + 1}?`;

        // Remove all listeners of the 'show solution' button, by cloning and replacing it.
        var modalShowSolutionButton = quizModalElem.querySelector(`#${quizId}-show-solution`);
        var clone = modalShowSolutionButton.cloneNode(true);
        modalShowSolutionButton.replaceWith(clone);
        modalShowSolutionButton = clone;

        // Add click event listener to the 'show solution' button.
        modalShowSolutionButton.addEventListener('click', function() {
            const question = questions[questionNumber];
            const correctAnswerText = question.correctAnswer;
            const correctAnswers = correctAnswerText.split(',').map(Number);
            for (let answerIdx = 0; answerIdx < question.answers.length; answerIdx++) {
                const answerNumber = answerIdx + 1;
                const answerElemId = `#${quizId}-question${questionNumber}-${answerNumber}`;
                const answerElem = quizElement.querySelector(answerElemId);
                const isCorrectAnswer = correctAnswers.includes(answerNumber);
                if (question.type === 'single-choice') {
                    if (isCorrectAnswer) {
                        answerElem.click();
                    }
                } else if (question.type === 'multiple-choice') {
                    if (answerElem.checked != isCorrectAnswer) {
                        answerElem.click();
                    }
                } else {
                    console.error('Unknown question type: ' + question.type);
                }
            }
        });
    });
}

function resetAnimation(element) {
    element.style.animation = 'none'; // Disable animation.
    element.offsetHeight; // Trigger reflow.
    element.style.animation = null; // Restore animation.
}
