<?php

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

use \grade_item;

class completionscanner 
{
    private static $mod_supported = [];
    private static $course_students = [];
    private $scanner = null;
    private $course = null;
    private $cm = 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(\completion_criteria $crit,$course){
        $this->courseid = $course->id;
        $this->course = $course;
        $this->modinfo = get_fast_modinfo($course);
        $this->crit = $crit;

        $this->completioninfo = new \completion_info($course);
        
        // Find a related scanner if the type is an activity type
        if($crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY){
            // First find the course module
            $this->cm = $this->modinfo->get_cm($crit->moduleinstance);
            $gi = grade_item::fetch(['itemtype' => 'mod', 'itemmodule' => $this->cm->modname, 'iteminstance' => $this->cm->instance, 'courseid' => $this->courseid]);
            if($gi !== false)
            {
                // Grade none items should not be relevant
                // Note that the grade status is probably only relevant if the item has not yet received a completion, but has been submitted
                if(($gi->gradetype == GRADE_TYPE_VALUE || $gi->gradetype == GRADE_TYPE_SCALE))
                {
                    // If it's a relevant grade type, initialize a scanner if possible
                    $this->gi = $gi;       
                    if(self::supported($gi->itemmodule)) {
                        $scannerclass = "\local_treestudyplan\\local\ungradedscanners\\{$gi->itemmodule}_scanner";
                        $this->scanner = new $scannerclass($gi);
                    }
                }
            }
        }

    }

    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(){
        
        // get completion info
        $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 {
                $completion = $this->completioninfo->get_user_completion($userid,$this->crit);
                
                if($this->crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY){
                    // If it's an activity completion, add all the relevant activities as sub-items
                    $completion_status = $this->completioninfo->get_grade_completion($this->cm,$userid);
                    
                    if($completion_status == COMPLETION_COMPLETE_PASS){
                        $completed_pass++;
                    } else if ($completion_status == COMPLETION_COMPLETE_FAIL){
                        $completed_fail++;
                    } else if ($completion_status == COMPLETION_COMPLETE){
                        $completed++;
                    }
                }
                else{
                    if($completion->is_complete()){
                        $completed++;
                    }
                }
            }
        }



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

}