<?php
// This file is part of the Studyplan plugin for Moodle
//
// 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 <https://www.gnu.org/licenses/>.

/**
 * Webservice class for managing studyplans
 * @package    local_treestudyplan
 * @copyright  2023 P.M. Kuipers
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

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

use local_treestudyplan\local\helpers\webservicehelper;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_description;
use core_external\external_value;
use core_external\external_multiple_structure;
use core_external\external_single_structure;
use core\context\system as context_system;
use core\context\course as context_course;
use core\context\coursecat as context_coursecat;

require_once($CFG->libdir . '/externallib.php');
require_once($CFG->libdir . '/badgeslib.php');
require_once($CFG->libdir . '/gradelib.php');
require_once($CFG->dirroot . '/course/modlib.php');

/**
 * Webservice class for managing studyplans
 */
class utilityservice extends external_api {
    /**
     * Capability required to edit study plans
     * @var string
     */
    const CAP_EDIT = "local/treestudyplan:editstudyplan";
    /**
     * Capability required to view studyplans (for other users)
     * @var string
     */
    const CAP_VIEW = "local/treestudyplan:viewuserreports";

    /**
     * Load moodle form
     * @param string $formname
     * @param string $params
     * @param string $ajaxformdata
     */
    protected static function load_mform($formname, $params, $ajaxformdata = null) {
        global $CFG;
        /*  We don't need to load the form php file (class autoloading will handle that)
            but we do need to check it's existence to give a nice developer warning
            and protect against some forms of hacking
        */
        $modmoodleform = "$CFG->dirroot/local/treestudyplan/classes/form/{$formname}.php";
        if (!file_exists($modmoodleform)) {
            throw new \moodle_exception('noformfile', 'local_treestudyplan', '', $formname);
        }

        $mformclassname = "\\local_treestudyplan\\form\\{$formname}";
        // Check if the form is a subclass of formbase.
        if (is_a($mformclassname, "\\local_treestudyplan\\form\\formbase", true)) {
            $jsonparams = json_decode($params);
            $mform = new $mformclassname($jsonparams, $ajaxformdata);
            return $mform;
        } else {
            throw new \moodle_exception('notformbase', 'local_treestudyplan');
        }
    }

    /**
     * Returns description of get_mform parameters
     *
     * @return external_function_parameters
     */
    public static function get_mform_parameters() {
        return new external_function_parameters([
            'formname' => new external_value(PARAM_COMPONENT, 'name of the treestudyplan form to parse'),
            'params' => new external_value(PARAM_RAW, 'JSON encoded parameters for form initialization'),
        ]);
    }

    /**
     * Get a HTML of a studyplan mform(s) via AJAX to insert into html
     *
     * @param string $formname Name of the form.
     * @param array $params Params needed to properly initialize the form
     * @return array HTML and JavaScript fragments for insertion into stuff.
     */
    public static function get_mform($formname, $params = '') {
        global $OUTPUT, $PAGE;

        external_api::validate_context(context_system::instance());
        require_login(null, false, null);

        // Hack alert: Set a default URL to stop the annoying debug.
        $PAGE->set_url('/');
        // Hack alert: Forcing bootstrap_renderer to initiate moodle page.
        $OUTPUT->header();
        /* Overwriting page_requirements_manager with the fragment one so only JS included from
           this point is returned to the user. */
        $PAGE->start_collecting_javascript_requirements();

        // Load the form before any output is started.
        $mform = self::load_mform($formname, $params);
        // Perform actual render.
        $html = $mform->render();

        $jsfooter = $PAGE->requires->get_end_code();
        $output = ['html' => $html, 'javascript' => $jsfooter];
        return $output;
    }

    /**
     * Returns description of get_mform() result value
     *
     * @return \core_externalexternal_description
     */
    public static function get_mform_returns() {
        return new external_single_structure(
            [
                'html' => new external_value(PARAM_RAW, 'HTML fragment.'),
                'javascript' => new external_value(PARAM_RAW, 'JavaScript fragment'),
            ]
        );
    }
    /**
     * Parameter description for webservice function submit_cm_editform
     */
    public static function submit_mform_parameters(): external_function_parameters {
        return new external_function_parameters([
            'formname' => new external_value(PARAM_COMPONENT, 'name of the treestudyplan form to parse'),
            'params' => new external_value(PARAM_RAW, 'JSON encoded parameters for form initialization'),
            "formdata" => new external_value(PARAM_RAW, 'url encoded form data'),
        ]);
    }

    /**
     * Return value description for webservice function submit_cm_editform
     */
    public static function submit_mform_returns(): external_description {
        return success::structure(); // Success structure includes data component which encodes date in json format.
    }

    /**
     * Submit specified form data into form
     * @param string $formname Name of the form.
     * @param array $params Params needed to properly initialize the form
     * @param mixed $formdata
     * @return array Success/fail structure
     */
    public static function submit_mform($formname, $params, $formdata) {
        external_api::validate_context(context_system::instance());
        require_login(null, false, null);

        $ajaxformdata = [];
        parse_str($formdata, $ajaxformdata);

        // Load the form, provide submitted form data and perform security checks.
        $mform = self::load_mform($formname, $params, $ajaxformdata);

        $return = $mform->process_submission();
        // Pass form processing result as success data component.
        return success::success($return)->model();
    }

    /**
     * Parameter description for webservice function submit_cm_editform
     */
    public static function getsettings_parameters(): external_function_parameters {
        return new external_function_parameters([
        ]);
    }

    /**
     * Return value description for webservice function submit_cm_editform
     */
    public static function getsettings_returns(): external_description {
        return new external_single_structure([
            "hivizdropslots" => new external_value(PARAM_BOOL, 'High visibility drop slots for items'),
            "toolboxleft" => new external_value(PARAM_BOOL, 'Start toolbox default on left side'),
            "toolboxcoursesonly" => new external_value(PARAM_BOOL, 'Show only courses in the toolbox'),
            "enablebadges" => new external_value(PARAM_BOOL, 'Badges are enabled in this instance'),
            "badges_allowcoursebadges" => new external_value(PARAM_BOOL, 'Course badges are enabled in this instance'),
            "showprevnextarrows" => new external_value(PARAM_BOOL, 'Show arrows next to the student selector'),
            "enableplansharing" => new external_value(PARAM_BOOL, 'Enable studyplan sharing with 3rd parties'),
            "defaultaggregation" => new external_value(PARAM_TEXT, 'Default aggregation method for new studyplans'),
        ]);
    }

    /**
     * Submit specified form data into form
     * @return array of settings
     */
    public static function getsettings() {
        global $CFG;
        external_api::validate_context(context_system::instance());
        require_login(null, false, null);

        return [
            "hivizdropslots" => get_config("local_treestudyplan", "hivizdropslots"),
            "toolboxleft" => get_config("local_treestudyplan", "toolboxleft"),
            "toolboxcoursesonly" => get_config("local_treestudyplan", "toolboxcoursesonly"),
            "enablebadges" => !empty($CFG->enablebadges),
            "badges_allowcoursebadges" => !empty($CFG->badges_allowcoursebadges),
            "showprevnextarrows" => get_config("local_treestudyplan", "showprevnextarrows"),
            "enableplansharing" => get_config("local_treestudyplan", "enableplansharing"),
            "defaultaggregation" => get_config("local_treestudyplan", "aggregation_mode"),
        ];
    }
}
