<?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/>.

/**
 * Developer CLI tool. Fill all the gradables in a study plan with random values
 * @package    local_treestudyplan
 * @copyright  2023 P.M. Kuipers
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace local_treestudyplan;

use local_treestudyplan\local\gradegenerator;
use core\context\module as context_module;
define('CLI_SCRIPT', true);
require(__DIR__ . '/../../../config.php');
require_once($CFG->libdir . '/clilib.php');
require_once($CFG->dirroot . '/mod/assign/locallib.php');

$usage = "Fill all the gradables in a study plan with random values

Usage:
    # php randomize_grades.php --studyplan=<shortname>  [--file|-f=userfile]
    # php randomize_grades.php --all|-a [--file|-f=userfile]
    # php randomize_grades.php --help|-h

Options:
    -h --help           Print this help.
    -f --file=<value>   Specify file name to store generated user specs in
    -d --dryrun         Do not store grades
";

[$options, $unrecognised] = cli_get_params([
    'help' => false,
    'dryrun' => false,
    'studyplan' => null,
    'all' => false,
    'file' => "/tmp/generategrades.json",
], [
    'h' => 'help',
    's' => 'studyplan',
    'a' => 'all',
    'f' => 'file',
    'd' => 'dryrun',
]);

if ($unrecognised) {
    $unrecognised = implode(PHP_EOL . '  ', $unrecognised);
    cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised));
}

if ($options['help']) {
    cli_writeln($usage);
    exit(2);
}

// Get administrator role and log in as.
$user = get_admin();

if (!$user) {
    cli_error("Unable to find admin user in DB.");
}

$auth = empty($user->auth) ? 'manual' : $user->auth;
if ($auth == 'nologin' || !is_enabled_auth($auth)) {
    cli_error(
        sprintf(
            "User authentication is either 'nologin' or disabled. Check Moodle authentication method for '%s'",
            $user->username
        )
    );
}

$authplugin = get_auth_plugin($auth);
$authplugin->sync_roles($user);
login_attempt_valid($user);
complete_user_login($user);

// Handle the studyplans.

if (empty($options['studyplan']) && empty($options["all"])) {
    cli_error('Missing mandatory argument studyplan.', 2);
}

if (!empty($options["all"])) {
    $plans = studyplan::find_all();
} else {
    $plans = studyplan::find_by_shortname($options["studyplan"]);
}

$generator = new gradegenerator();
$generator->from_file($options["file"]);

$assignments = [];

cli_writeln(count($plans) . " studyplans found:");
foreach ($plans as $plan) {
    cli_heading($plan->name());
    $users = $plan->find_linked_users();

    foreach ($plan->pages() as $page) {
        $lines = studyline::find_page_children($page);
        foreach ($lines as $line) {
            cli_writeln("  ** {$line->name()} **");
            $items = studyitem::find_studyline_children($line);
            foreach ($items as $item) {
                if ($item->type() == studyitem::COURSE) {
                    // Only handle courses for now.
                    $courseinfo = $item->getcourseinfo();
                    cli_writeln("    # {$courseinfo->shortname()}");

                    if ($courseinfo->course()->startdate <= time()) {
                        foreach ($users as $u) {
                            cli_writeln("      -> {$u->firstname} {$u->lastname} <-");
                            $gradables = gradeinfo::list_studyitem_gradables($item);
                            $gen = $generator->generate($u->username, $line->shortname(), $gradables);
                            foreach ($gen as $gg) {
                                $g = $gg->gi;
                                $gi = $g->get_gradeitem();

                                $name = $gi->itemname;
                                $grade = $gg->gradetext;
                                cli_write("        - {$name} = {$grade}");

                                // Check if the item is alreaady graded for this user.
                                $existing = $count = $DB->count_records_select(
                                    'grade_grades',
                                    'itemid = :gradeitemid AND finalgrade IS NOT NULL and userid = :userid',
                                    ['gradeitemid' => $gi->id, 'userid' => $u->id]
                                );

                                if (!$existing) {
                                    if ($gg->grade > 0) {
                                        if ($gi->itemmodule == "assign") {
                                            // If it is an assignment, submit though that interface .
                                            [$c, $cminfo] = get_course_and_cm_from_instance(
                                                $gi->iteminstance,
                                                $gi->itemmodule
                                            );
                                            $cmctx = context_module::instance($cminfo->id);
                                            $a = new \assign($cmctx, $cminfo, $c);

                                            $ug = $a->get_user_grade($u->id, true);
                                            $ug->grade = grade_floatval($gg->grade);
                                            $ug->grader = $USER->id;
                                            $ug->feedbacktext = nl2br(
                                                htmlspecialchars(
                                                    $gg->fb,
                                                    ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401
                                                )
                                            );
                                            $ug->feedbackformat = FORMAT_HTML;

                                            if (!$options["dryrun"]) {
                                                $a->update_grade($ug);

                                                grade_regrade_final_grades($c->id, $u->id, $gi);
                                                cli_writeln(" ... Stored");
                                            } else {
                                                cli_writeln(" ... (Dry Run)");
                                            }
                                        } else {
                                            // Otherwise, set the grade through the manual grading override.
                                            cli_writeln(" ... Cannot store");
                                        }
                                    } else {
                                        cli_writeln(" ... No grade");
                                    }
                                } else {
                                    cli_writeln(" ... Already graded");
                                }
                            }
                        }
                    } else {
                        cli_writeln("      Skipping since it has not started yet");
                    }
                }
            }
        }
    }
}

$generator->to_file($options["file"]);
