<?php

namespace local_treestudyplan\local\aggregators;

use \local_treestudyplan\courseinfo;
use \local_treestudyplan\gradeinfo;
use \local_treestudyplan\studyitem;
use \local_treestudyplan\completion;

class tristate_aggregator extends \local_treestudyplan\aggregator {
    public const DEPRECATED = true;
    private const DEFAULT_CONDITION = "50";

    public function needSelectGradables(){ return True;}
    public function isDeprecated() { return self::DEPRECATED;}
    public function useRequiredGrades() { return False;}
    public function useItemConditions() { return True;}

    protected function aggregate_completion(array $a, $condition = "50") {
        if(in_array($condition, ['ALL','67','50','ANY'])){
            // condition is one of the valid conditions
            $c_completed = 0;
            $c_excellent = 0;
            $c_progress = 0;
            $c_pending = 0;
            $count = sizeof($a);

            if($count > 0)
            {

                foreach($a as $c) {
                    $c_progress += ($c>=completion::PROGRESS)?1:0;
                    $c_completed += ($c>=completion::COMPLETED)?1:0;
                    $c_excellent += ($c>=completion::EXCELLENT)?1:0;
                    $c_pending += ($c>=completion::PENDING)?1:0;
                }

                $required = [
                    'ALL' => 1.00 * $count,
                    '67'  => 0.67 * $count,
                    '50'  => 0.50 * $count,
                    'ANY' => 1,
                    ][$condition];

                if($c_excellent >= $required) {
                    return completion::EXCELLENT;
                } else if ($c_completed >= $required) {
                    return completion::COMPLETED;
                } else {
                    // Return PROGRESS if one or more completions are COMPLETED or EXCELLENT, but the aggregation margin is not met
                    // state PROGRESS will not carry on if aggregations are chained
                    if($c_progress > 0){
                        return completion::PROGRESS;
                    } 
                    else if($c_pending > 0){
                        return completion::PENDING;
                    }
                    else {
                        return completion::INCOMPLETE;
                    }
                }
            }
            else {
                return completion::INCOMPLETE;
            }
        }
        else 
        {
            // indeterminable, return null
            return null;
        }
    }

    public function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid){
        $condition = $studyitem->conditions();
        if(empty($condition)){
            $condition = self::DEFAULT_CONDITION;
        }
        $list = [];
        foreach(gradeinfo::list_studyitem_gradables($studyitem) as $gi){
            $list[] = $this->grade_completion($gi,$userid);
        }
        $completion = self::aggregate_completion($list,$condition);
        return $completion;
    }

    public function aggregate_junction(array $completion, studyitem $studyitem, $userid){
        $completed = self::aggregate_completion($completion,$studyitem->conditions());
        // if null result (conditions are unknown/null) - default to ALL
        return isset($completed)?$completed:(self::aggregate_completion($completion,'ALL'));
    }

    public function grade_completion(gradeinfo $gradeinfo, $userid) {
        global $DB;
        $gradeitem = $gradeinfo->getGradeitem();
        $grade = $gradeitem->get_final($userid);

        if(empty($grade)){
            return completion::INCOMPLETE;
        }
        else if($grade->finalgrade === NULL)
        {
            // on assignments, grade NULL means a submission has not yet been graded,
            // but on quizes this can also mean a quiz might have been started
            // Therefor, we treat a NULL result as a reason to check the relevant gradingscanner for presence of pending items

            // Since we want old results to be visible until a pending item was graded, we only use this state here.
            // Pending items are otherwise expressly indicated by the "pendingsubmission" field in the user model
            if($gradeinfo->getGradingscanner()->pending($userid)){
                return completion::PENDING;
            } else {
                return completion::INCOMPLETE;
            }
            
        }
        else {
            $finalgrade = $grade->finalgrade;
            $scale = $gradeinfo->getScale();

            if($gradeitem->gradepass > 0)
            {
                // Base completion off of gradepass (if set)
                if($gradeitem->grademax > $gradeitem->gradepass && $finalgrade >= $gradeitem->grademax){
                    // If gradepass is configured 
                    return completion::EXCELLENT;
                }
                else if($finalgrade >= $gradeitem->gradepass){
                    return completion::COMPLETED;
                }
                else {
                    return completion::PROGRESS;
                }
            }
            else {
                // Blind assumptions:
                // over 55% of range is completed
                // over 85% of range is excellent
                $g = floatval($finalgrade - $gradeitem->grademin);
                $range = floatval($gradeitem->grademax - $gradeitem->grademin);
                $score = $g / $range;

                if($score > 0.85){
                    return completion::EXCELLENT;
                }
                else if($score > 0.55){
                    return completion::COMPLETED;
                }
                else {
                    return completion::PROGRESS;
                }
            }
        }
    }



}