<?php

namespace local_treestudyplan;
require_once($CFG->libdir.'/externallib.php');

use \grade_item;

// $gi->courseid, 
// $gi->itemmodule, 
// $gi->iteminstance
class gradingscanner 
{
    private static $mod_supported = [];
    private static $course_students = [];
    private $scanner = null;
    private $gi = null;
    private $pending_cache = [];

    public static function supported($mod){
        if(!array_key_exists($mod,self::$mod_supported)){
            self::$mod_supported[$mod] = class_exists("\local_treestudyplan\\local\\ungradedscanners\\{$mod}_scanner");
        }
        return self::$mod_supported[$mod];
    }

    public static function get_course_students($courseid){
        global $CFG;
        if(!array_key_exists($courseid,self::$course_students)){
            $students = [];
            $context = \context_course::instance($courseid);
            foreach (explode(',', $CFG->gradebookroles) as $roleid) {
                $roleid = trim($roleid);
                $students = array_keys(get_role_users($roleid, $context, false, 'u.id', 'u.id ASC'));
            }
            self::$course_students[$courseid] = $students;
        }
        return self::$course_students[$courseid];
    }

    public function __construct(grade_item $gi){
        $this->courseid = $gi->courseid;
        $this->gi = $gi;
        if(self::supported($gi->itemmodule)) {
            $scannerclass = "\local_treestudyplan\\local\ungradedscanners\\{$gi->itemmodule}_scanner";
            $this->scanner = new $scannerclass($gi);
        }
    }
    
    public function is_available(){
        return $this->scanner !== null;
    }

    public function pending($userid){
        if(!array_key_exists($userid, $this->pending_cache)){
            if($this->scanner === null) {
                $this->pending_cache[$userid] = false;
            }
            else {
                $this->pending_cache[$userid] = $this->scanner->has_ungraded_submission($userid);;    
            }
        }
        return $this->pending_cache[$userid];
    }    

    public static function structure($value=VALUE_OPTIONAL){
        return new \external_single_structure([
            "ungraded" => new \external_value(PARAM_INT, 'number of ungraded submissions'),
            "completed" => new \external_value(PARAM_INT, 'number of completed students'),
            "completed_pass" => new \external_value(PARAM_INT, 'number of completed-pass students'),
            "completed_fail" => new \external_value(PARAM_INT, 'number of completed-fail students'),
            "students" => new \external_value(PARAM_INT, 'number of students that should submit'),
        ],"details about gradable submissions",$value);        
    }

    public function model(){
        // Upda
        $students = self::get_course_students($this->courseid);
        $completed = 0;
        $ungraded = 0;
        $completed_pass = 0;
        $completed_fail = 0;
        foreach($students as $userid){
            if($this->pending($userid)){
                // First check if the completion needs grading
                $ungraded++;
            } else {
                $grade = $this->gi->get_final($userid);
                if(!is_numeric($grade->finalgrade) && empty($grade->finalgrade)){
                    //skip
                }
                else 
                {
                    //compare grade to minimum grade
                    if($this->grade_passed($grade)){
                        $completed_pass++;
                    } else {
                        $completed_fail++;
                    }
                }
            }
        }

        return [
            'ungraded' => $ungraded,
            'completed' => $completed,
            'completed_pass' => $completed_pass,
            'completed_fail' => $completed_fail,
            'students' => count($students),
        ];

    }

    // Function copied from bistate aggregator to avoid reference mazes
    private function grade_passed($grade){
        global $DB;
        $table = "local_treestudyplan_gradecfg";
        // first determine if we have a grade_config for this scale or this maximum grade
        $finalgrade = $grade->finalgrade;
        $scale = $this->gi->load_scale();
        if( isset($scale)){
            $gradecfg = $DB->get_record($table,["scale_id"=>$scale->id]);
        }
        else if($this->gi->grademin == 0)
        {
            $gradecfg = $DB->get_record($table,["grade_points"=>$this->gi->grademax]);
        }
        else 
        {
            $gradecfg = null;
        }

        // for point grades, a provided grade pass overrides the defaults in the gradeconfig
        // for scales, the configuration in the gradeconfig is leading

        if($gradecfg && (isset($scale) || $this->gi->gradepass == 0))
        {
            // if so, we need to know if the grade is 
            if($finalgrade >= $gradecfg->min_completed){
                return true;
            }
            else {
                return false;
            }
        }
        else if($this->gi->gradepass > 0)
        {
            $range = floatval($this->gi->grademax - $this->gi->grademin);
            // if no gradeconfig and gradepass is set, use that one to determine config.
            if($finalgrade >= $this->gi->gradepass){
                return true;
            }
            else {
                return false;
            }
        }
        else {
            // Blind assumptions if nothing is provided
            // over 55% of range is completed
            // if range >= 3 and failed is enabled, assume that this means failed
            $g = floatval($finalgrade - $this->gi->grademin);
            $range = floatval($this->gi->grademax - $this->gi->grademin);
            $score = $g / $range;

            if($score > 0.55){
                return true;
            }
            else {
                return false;
            }
        }
    }


}