<?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/>.
/**
 * Handle badge information
 * @package    local_treestudyplan
 * @copyright  2023 P.M. Kuipers
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace local_treestudyplan;
defined('MOODLE_INTERNAL') || die();

require_once($CFG->libdir.'/externallib.php');
use \core_badges\badge;

/**
 * Handle badge information in the same style as the other classes
 */
class badgeinfo {
    /**
     * Holds database record
     * @var \core_badges\badge
     */
    private $badge;

    /**
     * Maps badge status to strings
     * @var array
     */
    private const STATUSINFO = [
        BADGE_STATUS_INACTIVE => 'inactive',
        BADGE_STATUS_ACTIVE => 'active',
        BADGE_STATUS_INACTIVE_LOCKED => 'inactive',
        BADGE_STATUS_ACTIVE_LOCKED => 'active',
        BADGE_STATUS_ARCHIVED => 'archived',
    ];

    /**
     * Maps badge status to locked or not
     * @var array
     */
    private const LOCKEDINFO = [
        BADGE_STATUS_INACTIVE => 0,
        BADGE_STATUS_ACTIVE => 0,
        BADGE_STATUS_INACTIVE_LOCKED => 1,
        BADGE_STATUS_ACTIVE_LOCKED => 1,
        BADGE_STATUS_ARCHIVED => 1, // We don't want to edit archived badges anyway....     .
    ];

    /**
     * Construct new badgeinfo object
     * @param badge $badge Badge object to use
     */
    public function __construct(badge $badge) {
        $this->badge = $badge;
    }

    /**
     * Return full name
     * @return string
     */
    public function name() {
        return $this->badge->name;
    }

    /**
     * Get the badge id from the badge name
     * @param string $name Badge name
     * @return int Badge id
     */
    public static function id_from_name($name) {
        global $DB;

        return $DB->get_field("badge", "id", ['name' => $name]);
    }

    /**
     * Check if a given badge exists
     * @param int $id Badge id
     * @return bool
     */
    public static function exists($id) {
        global $DB;
        return is_numeric($id) && $DB->record_exists('badge', array('id' => $id));
    }

    /**
     * Webservice structure for editor info
     * @param int $value Webservice requirement constant
     */
    public static function editor_structure($value = VALUE_REQUIRED) : \external_description {
        return new \external_single_structure([
            "id" => new \external_value(PARAM_INT, 'id of badge'),
            "infolink" => new \external_value(PARAM_TEXT, 'badge issue information link', VALUE_OPTIONAL),
            "name" => new \external_value(PARAM_TEXT, 'badge name'),
            "status" => new \external_value(PARAM_TEXT, 'badge status'),
            "locked" => new \external_value(PARAM_TEXT, 'badge lock status'),
            "criteria" => new \external_multiple_structure(
                                new \external_value(PARAM_RAW, 'criteria text'), 'badge criteria', VALUE_OPTIONAL),
            "description" => new \external_value(PARAM_TEXT, 'badge description'),
            "imageurl" => new \external_value(PARAM_TEXT, 'url of badge image'),
            "studentcount" => new \external_value(PARAM_INT,
                                                  'number of studyplan students that can get this badge', VALUE_OPTIONAL),
            "issuedcount" => new \external_value(PARAM_INT,
                                                  'number of studyplan students that have got this badge', VALUE_OPTIONAL),
        ], "Badge info", $value);
    }

    /**
     * Webservice model for editor info
     * @param int[] $studentlist List of user id's to use for checking issueing progress within a study plan
     * @return array Webservice data model
     */
    public function editor_model(array $studentlist = null) {
        if ($this->badge->type == BADGE_TYPE_SITE) {
            $context = \context_system::instance();
        } else {
            $context = \context_course::instance($this->badge->courseid);
        }
        // If the user is viewing another user's badge and doesn't have the right capability return only part of the data.

        $criteria = [];
        foreach ($this->badge->get_criteria() as $bc) {
            $criteria[] = $bc->get_title()." ".$bc->get_details();
        }
        $model = [
            'id' => $this->badge->id,
            'infolink' => (new \moodle_url('/badges/overview.php', ['id' => $this->badge->id]))->out(false),
            'name' => $this->badge->name,
            'status' => self::STATUSINFO[$this->badge->status],
            'locked' => self::LOCKEDINFO[$this->badge->status],
            'criteria' => $criteria,
            'description' => $this->badge->description,
            'imageurl' => \moodle_url::make_pluginfile_url($context->id,
                                            'badges', 'badgeimage', $this->badge->id, '/', 'f1')->out(false),
        ];

        // Add badge issue stats if a studentlist is attached to the request.
        if (!empty($studentlist) && is_array($studentlist)) {
            $model['studentcount'] = count($studentlist);
            $model['issuedcount'] = $this->count_issued($studentlist);
        }

        return $model;
    }

    /**
     * Webservice structure for userinfo
     * @param int $value Webservice requirement constant
     */
    public static function user_structure($value = VALUE_REQUIRED) : \external_description {
        return new \external_single_structure([
            "id" => new \external_value(PARAM_INT, 'id of badge'),
            "infolink" => new \external_value(PARAM_TEXT, 'badge issue information link', VALUE_OPTIONAL),
            "name" => new \external_value(PARAM_TEXT, 'badge name'),
            "criteria" => new \external_multiple_structure(
                                new \external_value(PARAM_RAW, 'criteria text'),
                            'badge criteria', VALUE_OPTIONAL),
            "description" => new \external_value(PARAM_TEXT, 'badge description'),
            "imageurl" => new \external_value(PARAM_TEXT, 'url of badge image'),
            "issued" => new \external_value(PARAM_BOOL, 'badge is issued'),
            "dateissued" => new \external_value(PARAM_TEXT, 'date the badge was issued', VALUE_OPTIONAL),
            "dateexpire" => new \external_value(PARAM_TEXT, 'date the badge will expire', VALUE_OPTIONAL),
            "uniquehash" => new \external_value(PARAM_TEXT, 'badge issue hash', VALUE_OPTIONAL),
            "issuedlink" => new \external_value(PARAM_TEXT, 'badge issue information link', VALUE_OPTIONAL),
        ], "Badge info", $value);
    }

    /**
     * Webservice model for user info
     * @param int $userid ID of user to check specific info for
     * @return array Webservice data model
     */
    public function user_model($userid) {
        global $DB;
        if ($this->badge->type == BADGE_TYPE_SITE) {
            $context = \context_system::instance();
        } else {
            $context = \context_course::instance($this->badge->courseid);
        }

        $issued = $this->badge->is_issued($userid);

        // If the user is viewing another user's badge and doesn't have the right capability return only part of the data.
        $criteria = [];
        foreach ($this->badge->get_criteria() as $bc) {
            $criteria[] = $bc->get_title()."".$bc->get_details();
        }
        $badge = [
            'id' => $this->badge->id,
            'name' => $this->badge->name,
            'description' => $this->badge->description,
            'imageurl' => \moodle_url::make_pluginfile_url($context->id,
                                                           'badges',
                                                           'badgeimage',
                                                           $this->badge->id, '/', 'f1'
                                                           )->out(false),
            'criteria' => $criteria,
            'issued' => $issued,
            'infolink' => (new \moodle_url('/badges/overview.php', ['id' => $this->badge->id]))->out(false),
        ];

        if ($issued) {
            $issueinfo = $DB->get_record('badge_issued', array('badgeid' => $this->badge->id, 'userid' => $userid));
            $badge['dateissued'] = date("Y-m-d", $issueinfo->dateissued);
            if ($issueinfo->expiredate) {
                $badge['dateexpire'] = date("Y-m-d", $issueinfo->dateexpire);
            }
            $badge['uniquehash'] = $issueinfo->uniquehash;
            $badge['issuedlink'] = (new \moodle_url('/badges/badge.php', ['hash' => $issueinfo->uniquehash]))->out(false);
        }

        return $badge;
    }

    /**
     * Count how many of the students in the array have this badge issued
     * @param int[] $studentids List of user id's to check
     * @return int
     */
    public function count_issued(array $studentids) {
        $issuecount = 0;

        foreach ($studentids as $userid) {
            if ($this->badge->is_issued($userid)) {
                $issuecount++;
            }
        }
        return $issuecount;
    }

}