<?php
// This file is part of mod_offlinequiz for 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/>.

/**
 * Step definitions for offlinequiz behat features.
 *
 * @package       mod_offlinequiz
 * @subpackage    offlinequiz
 * @author        Juergen Zimmer <zimmerj7@univie.ac.at>
 * @copyright     2015 Academic Moodle Cooperation {@link http://www.academic-moodle-cooperation.org}
 * @since         Moodle 2.9
 * @license       http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
use Behat\Mink\Exception\ExpectationException;
use function PHPUnit\Framework\throwException;
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
require_once(__DIR__ . '/../../../../question/tests/behat/behat_question_base.php');

use Behat\Step\Given,
    Behat\Gherkin\Node\TableNode,
    Behat\Behat\Tester\Exception\PendingException;


/**
 * Steps definitions related to mod_offlinequiz.
 *
 * @copyright 2015 Juergen Zimmer
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class behat_mod_offlinequiz extends behat_question_base {
    /**
     * Adds the specified questions to offlinequiz
     *
     *
     * @Given /^the following questions are added to the offlinequiz "(?P<entityname>.+)"$/
     *
     * @param string $entityname The name of the offlinequiz
     * @param TableNode $data
     */
    #[\core\attribute\example('The following questions are added to the offlinequiz "testofflinequiz"
      | questioncategory  | questionname     | group | maxmark |
      | Test questions    | Multi-choice-001 | A     | 1       |')]
    public function the_following_questions_are_added_to_the_offlinequiz($entityname, $data): void {
        global $CFG;
        $groupnumbers = ['A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6];
        require_once($CFG->dirroot . '/mod/offlinequiz/locallib.php');
        global $DB;
        $offlinequiz = $DB->get_record('offlinequiz', ['name' => $entityname]);
        if (!$offlinequiz) {
            throw new PendingException('unknown offlinequiz name');
        }
        $cm = get_coursemodule_from_instance('offlinequiz', $offlinequiz->id);
        $offlinequiz->cmid = $cm->id;
        $columns = array_flip($data->getRow(0));
        $rows = $data->getRows();
        unset($rows[0]);

        foreach ($rows as $row) {
            if (array_key_exists('maxmark', $columns)) {
                $maxmark = $row[$columns['maxmark']];
            } else {
                $maxmark = 0;
            }
            $groupnummber = $groupnumbers[$row[$columns['group']]];
            if (!$groupnummber) {
                $groupnumber = 1;
            }
            $questioncategory = $DB->get_record('question_categories', ['name' => $row[$columns['questioncategory']]]);
            $addquestion = $DB->get_field('question', 'id', ['name' => $row[$columns['questionname']]]);
            $offlinequiz->groupid = $DB->get_field(
                'offlinequiz_groups',
                'id',
                ['offlinequizid' => $offlinequiz->id, 'groupnumber' => $groupnummber]
            );
            offlinequiz_add_offlinequiz_question($addquestion, $offlinequiz, 0, $maxmark);
        }
    }


    /**
     * Delete a question on the Edit offlinequiz page by first clicking on the Delete icon,
     * then clicking one of the "After ..." links.
     * @When /^I delete "(?P<question_name>(?:[^"]|\\")*)" in the offlinequiz by clicking the delete icon$/
     * @param string $questionname the name of the question we are looking for.
     */
    public function i_delete_question_by_clicking_the_delete_icon($questionname) {
        $slotxpath = "//li[contains(@class, ' slot ') and contains(., '" . $this->escape($questionname) .
                "')]";
        $deletexpath = "//a[contains(@class, 'editing_delete')]";

        $this->execute("behat_general::i_click_on", [$slotxpath . $deletexpath, "xpath_element"]);

        // Wait for the dialogue to exist before clicking on the 'Yes' button to avoid random failures.
        $this->execute('behat_general::wait_until_exists', [".modal-content", "css_element"]);

        $this->execute(
            'behat_general::i_click_on_in_the',
            ["Yes", "button", "Confirm", "dialogue"]
        );
    }

    /**
     * Change groups by selecting it in the group select
     * @When /^I switch to group "(?P<groupname>(?:[^"]|\\")*)"$/
     * @param string $groupname the name of the group we are switching to
     */
    public function i_switch_to_group($groupname) {

        $page = $this->getSession()->getPage();

        $select = $page->findField('groupnumber');
        if (!$select) {
            throw new \Exception('Could not find the group selector.');
        }

        $select->selectOption('Group ' . $groupname, false);
    }

    /**
     * Adds the specified questions to offlinequiz
     *
     *
     * @When /^I duplicate the following activities:$/
     *
     * @param string $data The name of the offlinequizes
     * @param TableNode $data
     */
    #[\core\attribute\example('I duplicate the following activities:
      | name        |
      | duplicate 1 |
      | duplicate 2 |')]
    public function duplicate_the_following_activities($data): void {
        $this->execute('behat_general::i_click_on', [get_string('bulkactions'), 'button']);
        $rows = $data->getRows();
        unset($rows[0]);

        foreach ($rows as $row) {
            $xpath = "//div[contains(@class, 'activity-grid')][.//*[@data-value='{$row[0]}']]";
            $this->execute('behat_general::i_click_on', [ $xpath, 'xpath_element']);
        }
        $this->execute('behat_general::i_click_on', [get_string('duplicate'), 'button']);
    }

    /**
     * Verifies that the given questions cannot be added.
     *
     * @Then /^I cannot add the following questions:$/
     *
     * @param TableNode $table The table of questions that needs to be checked.
     */
    public function i_cannot_add_the_following_questions(TableNode $table) {
        // Open the question bank dialog once.
        $this->execute('behat_general::i_click_on', ['Add', 'link']);
        $this->execute('behat_general::i_click_on', ['from question bank', 'link']);

        foreach ($table->getHash() as $row) {
            $this->execute('behat_general::i_click_on', ['Switch bank', 'button']);
            $container = $this->find('css_element', '.course-shared-banks');
            $link = $container->findLink($row['questionbank']);
            if (!$link) {
                throw new ExpectationException(
                    "Link '{$row['questionbank']}' not found.",
                    $this->getSession()
                );
            }
            $link->click();
            $this->select_question_category($row["questioncategory"]);
            $xpath = "//tr[.//td[contains(@class,'questionnametext')]" .
                "[contains(normalize-space(.), '{$row['questionname']}')]]" .
                "//input[contains(@class,'select-multiple-checkbox')]";

            $this->execute(
                'behat_general::the_element_should_be_disabled',
                [$xpath, 'xpath_element']
            );
        }
    }

    /**
     * Select the question category in the select menu
     * @param string $category
     * @throws ExpectationException
     * @return void
     */
    private function select_question_category(string $category): void {
        // Remove existing category selection.
        $removebutton = $this->find(
            'css_element',
            '.form-autocomplete-selection .icon.fa-times'
        );

        if ($removebutton) {
            $removebutton->click();
        }

        // Type the new category.
        $input = $this->find(
            'css_element',
            'input[data-fieldtype="autocomplete"]'
        );

        $input->click();
        $input->setValue($category);

        // Wait for suggestions.
        $this->getSession()->wait(
            5000,
            "document.querySelector('.form-autocomplete-suggestions li[role=\"option\"]') !== null"
        );
        $xpath = "//ul[contains(@class,'form-autocomplete-suggestions')]" .
        "//li[@role='option' and contains(normalize-space(.), '{$category}')]";
        // Select the category suggestion.
        $this->getSession()->wait(5000, "
            document.evaluate(
                " . json_encode($xpath) . ",
                document,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue !== null
        ");
        $this->find('xpath_element', $xpath)->click();
    }
}
