<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

namespace qtype_ordering\output;

use qbehaviour_walkthrough_test_base;
use qtype_ordering\question_hint_ordering;
use test_question_maker;
use qtype_ordering_question;
use qtype_ordering_test_helper;

defined('MOODLE_INTERNAL') || die();

global $CFG;
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');

/**
 * Test the feedback exporter.
 *
 * @package   qtype_ordering
 * @copyright 2023 Mathew May <mathew.solutions>
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @covers    \qtype_ordering\output\renderable_base
 * @covers    \qtype_ordering\output\feedback
 */
final class feedback_test extends qbehaviour_walkthrough_test_base {
    /** @var array The correct answers for the question, added to quickly reference. */
    const CORRECTANSWERS = [
        0 => [
            'answertext' => 'Modular',
        ],
        1 => [
            'answertext' => 'Object',
        ],
        2 => [
            'answertext' => 'Oriented',
        ],
        3 => [
            'answertext' => 'Dynamic',
        ],
        4 => [
            'answertext' => 'Learning',
        ],
        5 => [
            'answertext' => 'Environment',
        ],
    ];

    /**
     * Test the exported data for the template that renders the feedback test to a given question attempt.
     *
     * @dataProvider export_for_template_provider
     * @param array $answeritems The array of ordered answers.
     * @param int $gradingtype Grading type.
     * @param array $testoptions Do we want to change direction, is it in progress and do we want feedback.
     * @param array $expected The expected exported data.
     * @return void
     */
    public function test_export_for_template(array $answeritems, int $gradingtype, array $testoptions, array $expected): void {
        global $PAGE;

        $question = test_question_maker::make_question('ordering');
        $question->hints = [
            new question_hint_ordering(13, 'This is the first hint.', FORMAT_HTML, true, false, true),
            new question_hint_ordering(14, 'This is the second hint.', FORMAT_HTML, false, false, false),
        ];
        $question->layouttype = $testoptions['rot'] === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL :
            qtype_ordering_question::LAYOUT_VERTICAL;

        // If we need to access the attempt midway through, we need a flow where we don't grade instantly.
        if (!$testoptions['inprogress']) {
            $qa = new \testable_question_attempt($question, 0);
            $step = new \question_attempt_step();
            $qa->add_step($step);
            $qa->set_behaviour($question->make_behaviour($qa, 'interactive'));
            $question->gradingtype = $gradingtype;
            $question->start_attempt($step, 1);
            // Process a response and check the expected result.
            $keys = implode(',', array_keys($answeritems));
            $values = array_values($answeritems);
            $step->set_qt_var('_currentresponse', $keys);

            list($fraction, $state) = $question->grade_response(qtype_ordering_test_helper::get_response($question, $values));
            $qa->get_last_step()->set_state($state);
            $attempt = $qa;
        } else {
            $this->start_attempt_at_question($question, 'interactive');
            $response = qtype_ordering_test_helper::get_response($question, array_values($answeritems));
            $this->process_submission(array_merge(['-submit' => 1], $response));
            $attempt = $this->get_question_attempt();
            // Omit the numparts as we are not testing it here, and it can be a bit flaky when manually processing an attempt.
            $this->displayoptions->numpartscorrect = false;
        }
        if (!$testoptions['feedback']) {
            $this->displayoptions->feedback = false;
        }

        $renderer = $PAGE->get_renderer('core');
        $feedbackobj = new feedback($attempt, $this->displayoptions);
        $actual = $feedbackobj->export_for_template($renderer);

        $this->assertEquals($expected, $actual);
    }

    /**
     * Data provider for the test_export_for_template test.
     *
     * @return array
     */
    public static function export_for_template_provider(): array {
        global $CFG;
        require_once($CFG->dirroot . '/question/type/ordering/question.php');

        return [
            'Do not show partial or wrong' => [
                [13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 16 => 'Dynamic', 17 => 'Learning', 18 => 'Environment'],
                qtype_ordering_question::GRADING_RELATIVE_NEXT_EXCLUDE_LAST,
                ['rot' => 'horizontal', 'inprogress' => false, 'feedback' => true],
                [
                    'specificfeedback' => 'Well done!',
                    'numpartscorrect' => [
                        'numcorrect' => 5,
                        'numpartial' => 0,
                        'numincorrect' => 0,
                    ],
                    'specificgradedetailfeedback' => [
                        'showpartialwrong' => 0,
                    ],
                    'generalfeedback' => '<div class="clearfix">The correct answer is ' .
                        '"Modular Object Oriented Dynamic Learning Environment".</div>',
                    'rightanswer' => [
                        'hascorrectresponse' => true,
                        'showcorrect' => false,
                    ],
                ],
            ],
            'Partially correct question attempt (horizontal layout). Relative to ALL the previous and next items' => [
                [13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 17 => 'Learning', 16 => 'Dynamic', 18 => 'Environment'],
                qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT,
                ['rot' => 'horizontal', 'inprogress' => false, 'feedback' => true],
                [
                    'specificfeedback' => 'Parts, but only parts, of your response are correct.',
                    'numpartscorrect' => [
                        'numcorrect' => 4,
                        'numpartial' => 2,
                        'numincorrect' => 0,
                    ],
                    'specificgradedetailfeedback' => [
                        'showpartialwrong' => 1,
                        'gradingtype' => 'Grading type: Relative to ALL the previous and next items',
                        'orderinglayoutclass' => 'horizontal',
                        'scoredetails' => [
                            0 => [
                                'score' => 5,
                                'maxscore' => 5,
                                'percent' => 100.00,
                            ],
                            1 => [
                                'score' => 5,
                                'maxscore' => 5,
                                'percent' => 100.00,
                            ],
                            2 => [
                                'score' => 5,
                                'maxscore' => 5,
                                'percent' => 100.00,
                            ],
                            3 => [
                                'score' => 4,
                                'maxscore' => 5,
                                'percent' => 80.00,
                            ],
                            4 => [
                                'score' => 4,
                                'maxscore' => 5,
                                'percent' => 80.00,
                            ],
                            5 => [
                                'score' => 5,
                                'maxscore' => 5,
                                'percent' => 100.00,
                            ],
                        ],
                        'gradedetails' => 93.0,
                        'totalscore' => 28,
                        'totalmaxscore' => 30,
                    ],
                    'generalfeedback' => '<div class="clearfix">The correct answer is ' .
                        '"Modular Object Oriented Dynamic Learning Environment".</div>',
                    'rightanswer' => [
                        'hascorrectresponse' => true,
                        'showcorrect' => true,
                        'orderinglayoutclass' => 'horizontal',
                        'correctanswers' => self::CORRECTANSWERS,
                    ],
                ],
            ],
            'Partially correct question attempt in progress (horizontal layout). Relative to ALL the previous and next ' .
            'items with hints' => [
                [13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 17 => 'Learning', 16 => 'Dynamic', 18 => 'Environment'],
                qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT,
                ['rot' => 'horizontal', 'inprogress' => true, 'feedback' => true],
                [
                    'specificfeedback' => 'Parts, but only parts, of your response are correct.',
                    'specificgradedetailfeedback' => [
                        'showpartialwrong' => 0,
                    ],
                    'generalfeedback' => '<div class="clearfix">The correct answer is ' .
                        '"Modular Object Oriented Dynamic Learning Environment".</div>',
                    'rightanswer' => [
                        'hascorrectresponse' => true,
                        'showcorrect' => false,
                    ],
                    'hint' => 'This is the first hint.',
                ],
            ],
            'Partially correct question attempt in progress (No feedback). Relative to ALL the previous and next items' => [
                [13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 17 => 'Learning', 16 => 'Dynamic', 18 => 'Environment'],
                qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT,
                ['rot' => 'horizontal', 'inprogress' => false, 'feedback' => false],
                [
                    'generalfeedback' => '<div class="clearfix">The correct answer is ' .
                        '"Modular Object Oriented Dynamic Learning Environment".</div>',
                    'rightanswer' => [
                        'hascorrectresponse' => true,
                        'showcorrect' => true,
                        'orderinglayoutclass' => 'horizontal',
                        'correctanswers' => self::CORRECTANSWERS,
                    ],
                    'numpartscorrect' => [
                        'numcorrect' => 4,
                        'numpartial' => 2,
                        'numincorrect' => 0,
                    ],
                ],
            ],
            'Incorrect question attempt (horizontal layout). Relative to ALL the previous and next items' => [
                [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'],
                qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT,
                ['rot' => 'horizontal', 'inprogress' => false, 'feedback' => true],
                [
                    'specificfeedback' => 'Parts, but only parts, of your response are correct.',
                    'numpartscorrect' => [
                        'numcorrect' => 0,
                        'numpartial' => 6,
                        'numincorrect' => 0,
                    ],
                    'specificgradedetailfeedback' => [
                        'showpartialwrong' => 1,
                        'gradingtype' => 'Grading type: Relative to ALL the previous and next items',
                        'orderinglayoutclass' => 'horizontal',
                        'scoredetails' => [
                            0 => [
                                'score' => 4,
                                'maxscore' => 5,
                                'percent' => 80.00,
                            ],
                            1 => [
                                'score' => 3,
                                'maxscore' => 5,
                                'percent' => 60.00,
                            ],
                            2 => [
                                'score' => 3,
                                'maxscore' => 5,
                                'percent' => 60.00,
                            ],
                            3 => [
                                'score' => 4,
                                'maxscore' => 5,
                                'percent' => 80.0,
                            ],
                            4 => [
                                'score' => 4,
                                'maxscore' => 5,
                                'percent' => 80.00,
                            ],
                            5 => [
                                'score' => 2,
                                'maxscore' => 5,
                                'percent' => 40.0,
                            ],
                        ],
                        'gradedetails' => 67.0,
                        'totalscore' => 20,
                        'totalmaxscore' => 30,
                    ],
                    'generalfeedback' => '<div class="clearfix">The correct answer is ' .
                        '"Modular Object Oriented Dynamic Learning Environment".</div>',
                    'rightanswer' => [
                        'hascorrectresponse' => true,
                        'showcorrect' => true,
                        'orderinglayoutclass' => 'horizontal',
                        'correctanswers' => self::CORRECTANSWERS,
                    ],
                ],
            ],
            'Incorrect question attempt (vertical layout). Grading type: Relative to the next item (excluding last)' => [
                [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'],
                qtype_ordering_question::GRADING_RELATIVE_NEXT_EXCLUDE_LAST,
                ['rot' => 'vertical', 'inprogress' => false, 'feedback' => true],
                [
                    'specificfeedback' => 'Parts, but only parts, of your response are correct.',
                    'numpartscorrect' => [
                        'numcorrect' => 1,
                        'numpartial' => 0,
                        'numincorrect' => 4,
                    ],
                    'specificgradedetailfeedback' => [
                        'showpartialwrong' => 1,
                        'gradingtype' => 'Grading type: Relative to the next item (excluding last)',
                        'orderinglayoutclass' => 'vertical',
                        'scoredetails' => [
                            0 => [
                                'score' => 0,
                                'maxscore' => 1,
                                'percent' => 0.0,
                            ],
                            1 => [
                                'score' => 0,
                                'maxscore' => 1,
                                'percent' => 0.0,
                            ],
                            2 => [
                                'score' => 0,
                                'maxscore' => 1,
                                'percent' => 0.0,
                            ],
                            3 => [
                                'score' => 1,
                                'maxscore' => 1,
                                'percent' => 100.0,
                            ],
                            4 => [
                                'score' => 'No score',
                                'maxscore' => null,
                                'percent' => 0,
                            ],
                            5 => [
                                'score' => 0,
                                'maxscore' => 1,
                                'percent' => 0.0,
                            ],
                        ],
                        'gradedetails' => 20.0,
                        'totalscore' => 1,
                        'totalmaxscore' => 5,
                    ],
                    'generalfeedback' => '<div class="clearfix">The correct answer is ' .
                        '"Modular Object Oriented Dynamic Learning Environment".</div>',
                    'rightanswer' => [
                        'hascorrectresponse' => true,
                        'showcorrect' => true,
                        'orderinglayoutclass' => 'vertical',
                        'correctanswers' => self::CORRECTANSWERS,
                    ],
                ],
            ],
        ];
    }
}
