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

/**
 * Class to find and cache which studyplans a teacher is teaching courses in
 * @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 Exception;
use core\context;
use core\context\system as context_system;
use core\context\course as context_course;
use core\context\coursecat as context_coursecat;

/**
 * Class to find and cache which studyplans a teacher is teaching courses in
 */
class teachingfinder {
    /**
     * Table name used for caching teacher info
     * @var string
     */
    /** @var string */
    const TABLE = "local_treestudyplan_teachers";

    /**
     * List all studyplans the current user is teaching
     * (Updates the cache if no results are found the first time)
     * @return studyplan[] List of  studyplans
     */
    public static function list_my_plans() {
        global $USER, $DB;
        $userid = $USER->id;

        $records = $DB->get_records(self::TABLE, ['teacher_id' => $userid]);
        if (count($records) == 0) {
            // Initiate a search if the cache is empty.
            self::update_teaching_cache($userid);
            $records = $DB->get_records(self::TABLE, ['teacher_id' => $userid]);
        }
        $list = [];
        foreach ($records as $r) {
            try {
                $list[] = studyplan::find_by_id($r->studyplan_id);
            } catch (\dml_missing_record_exception $x) {
                // Delete record if not found.
                $DB->delete_records(self::TABLE, ["id" => $r->id]);
            }
        }
        return $list;
    }

    /**
     * Check if a user is teaching in a specific studyplan
     * (Does not update the cache if results are 0)
     * @param studyplan $plan Studyplan to check
     * @param int $userid UserId to check for
     * @return bool If teaching in this plan
     */
    public static function is_teaching_studyplan(studyplan $plan, $userid) {
        global $DB;
        $count = $DB->count_records(self::TABLE, ['teacher_id' => $userid, "studyplan_id" => $plan->id()]);
        return ($count > 0) ? true : false;
    }

    /**
     * Check if a user is teaching courses in any studyplan
     * (Does not update the cache if results are 0)
     * @param int $userid UserId to check for
     * @return bool If teaching in any plan
     */
    public static function is_teaching($userid) {
        global $DB;
        $count = $DB->count_records(self::TABLE, ['teacher_id' => $userid]);
        return ($count > 0) ? true : false;
    }

    /**
     * Check if current user is teaching in a specific studyplan
     * (Does not update the cache if results are 0)
     * @param studyplan $plan Studyplan to check
     * @return bool If teaching in this plan
     */
    public static function am_teaching_studyplan(studyplan $plan) {
        global $USER;
        return self::is_teaching_studyplan($plan, $USER->id);
    }

    /**
     * Check if current user is teaching courses in any studyplan
     * (Does not update the cache if results are 0)
     * @return bool If teaching in any studyplan
     */
    public static function am_teaching() {
        global $USER;
        return self::is_teaching($USER->id);
    }

    /**
     * Check if a user is teaching in a specific course
     * @param int $courseid ID of the course
     * @param int $userid ID of the user
     * @return bool True if teaching in the course
     */
    public static function is_teaching_course($courseid, $userid) {
        $coursecontext = context_course::instance($courseid);
        return is_enrolled($coursecontext, $userid, 'mod/assign:grade');
    }

    /**
     * Check if current user is teaching in a specific course
     * @param int $courseid ID of the course
     * @return bool True if teaching in the course
     */
    public static function am_teaching_course($courseid) {
        global $USER;
        return self::is_teaching_course($courseid, $USER->id);
    }

    /**
     * Find The active studyplan pages where the specified user is a teacher
     * (Has the  mod/assign::grade capability in one of the linked courses)
     * @param int $userid The userid to check teacher rights for
     * @return int[] List of page id's a teacher is teaching courses in
     */
    public static function update_teaching_cache($userid) {
        global $DB;
        $list = [];

        // First find all active study plans.
        // Use string now in YYYY-MM-DD format to support multidb.
        $now = (new \DateTime())->format("Y-m-d");
        $sql = "SELECT p.id FROM {local_treestudyplan_page} p
                WHERE startdate <= :snow and enddate >= :enow";
        $pageids = $DB->get_fieldset_sql($sql, ["snow" => $now, "enow" => $now]);

        // Then parse them to see if the user has the grading permission in any of them .
        // (Which would make them a teacher for all intents and purposes).

        foreach ($pageids as $pageid) {
            $sql = "SELECT i.course_id FROM {local_treestudyplan_item} i
                    INNER JOIN {local_treestudyplan_line} l ON i.line_id = l.id
                    WHERE l.page_id = :page_id AND i.course_id IS NOT NULL";
            $courseids = $DB->get_fieldset_sql($sql, ["page_id" => $pageid]);

            $linked = false;
            foreach ($courseids as $cid) {
                if (self::is_teaching_course($cid, $userid)) {
                    $linked = true;
                    break; // No need to search further.
                }
            }

            if ($linked) {
                $list[] = $pageid;
            }
        }

        // Now, clear the database of all records for this user.
        $DB->delete_records(self::TABLE, ["teacher_id" => $userid]);
        // And add new records for the found studyplans.
        $now = time();
        foreach ($list as $pageid) {
            // Retrieve the studyplan id from the page.
            $planid = $DB->get_field("local_treestudyplan_page", "studyplan_id", ["id" => $pageid]);
            $DB->insert_record(self::TABLE, ["teacher_id" => $userid, "studyplan_id" => $planid, "update_time" => $now]);
        }

        return $list;
    }

    /**
     * List of recognized teacher id's
     * @return int[]
     */
    public static function list_teacher_ids() {
        global $DB;
        return $DB->get_fieldset_sql("SELECT DISTINCT teacher_id FROM {" . self::TABLE . "}");
    }

    /**
     * Get the last time of update for the specified teacher
     * @param int $teacherid User id of teacher
     * @return int Unix timestamp
     */
    public static function get_update_time($teacherid): int {
        global $DB;
        $r = $DB->get_field_sql(
            "SELECT MIN(update_time) FROM {" . self::TABLE . "} WHERE teacher_id=:teacher_id",
            ["teacher_id" => $teacherid]
        );
        return (int)($r->update_time);
    }
}
