<?php
// This file is part of Moodle - http://moodle.org/
//
// 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 <http://www.gnu.org/licenses/>.

namespace quizaccess_quilgo\local\report;

use moodle_url;
use table_sql;
use html_writer;

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

// Starting moodle 4.2, 'quiz_attempt' from autoloader is depcrecated. Suggested to use from 'mod\quiz_attempt'.
require_once($CFG->libdir.'/tablelib.php');
require_once($CFG->dirroot. '/mod/quiz/accessrule/quilgo/lib.php');
if (class_exists('mod_quiz\quiz_attempt')) {
    class_alias('mod_quiz\quiz_attempt', '\quiz_attempt_alias');
} else {
    require_once($CFG->dirroot . '/mod/quiz/locallib.php');
    class_alias('\quiz_attempt', '\quiz_attempt_alias');
}

/**
 * Table builder for proctoring report list
 * @package     quizaccess_quilgo
 * @copyright   2023 Native Platform Ltd <hello@quilgo.com>
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class report_list extends table_sql {

    /**
     * @var int course id
     */
    protected $cid;

    /**
     * @var int course module id
     */
    protected $cmid;

    /**
     * @var int quiz id
     */
    protected $qid;

    /**
     * @var object quiz object data
     */
    protected $quizobj;

    /**
     * @var string report url
     */
    protected $repurl;

    /**
     * @var int show record row per page
     */
    protected $perpage = 20;

    /**
     * @var bool flag for empty/not the records
     */
    protected $isrecordexists = false;

    /**
     * Init some properties and base table data
     * @param int $cid course id
     * @param int $cmid course module id
     * @param int $qid quiz id
     * @param object $quizobj quiz object data
     * @return void
     */
    public function __construct($cid, $cmid, $qid, $quizobj) {
        parent::__construct('quilgo-report-table');

        $this->cid = $cid;
        $this->cmid = $cmid;
        $this->qid = $qid;
        $this->quizobj = $quizobj;
        $this->repurl = quizaccess_quilgo_get_report_url($this->cid, $this->cmid, $this->qid);
        $this->inittable();
    }

    /**
     * Build sql properties like fields, from, and conditions
     * @return array
     */
    protected function build_sql_properties() {
        global $DB;

        $nameconcatsql = $DB->sql_concat_join("' '", ['u.firstname', 'u.lastname']);

        $fields = " a.id, u.id AS user_id, u.email, $nameconcatsql AS userfullname,
                    a.attempt, a.sumgrades, a.timestart, a.timefinish,
                    a.timefinish - a.timestart AS timetakens, a.preview,
                    r.camera_enabled, r.generate_status, r.stat";

        $from = " {quiz_attempts} a
                    JOIN {user} u ON u.id = a.userid
                    JOIN {quizaccess_quilgo_reports} r ON r.attemptid = a.id
        ";

        $quizid = $this->quizobj->get_quiz()->id;
        $attemptfinishedstate = \quiz_attempt_alias::FINISHED;

        $where = "r.plasmsessionid IS NOT NULL AND a.quiz = :quizid";
        $params = ["quizid" => $quizid];

        $where .= " AND a.state = :attemptfinishedstate";
        $params["attemptfinishedstate"] = $attemptfinishedstate;

        return [$fields, $from, $where, $params];
    }

    /**
     * Define headers, columns, and other table properties (e.g sql, base url)
     * @return void
     */
    protected function inittable() {
        global $DB;

        list($fields, $from, $where, $params) = $this->build_sql_properties();
        $row = $DB->get_record_sql("SELECT $fields FROM $from WHERE $where", $params, IGNORE_MULTIPLE);
        if (empty($row)) {
            return;
        }

        $this->isrecordexists = true;
        $this->set_sql($fields, $from, $where, $params);
        $this->set_count_sql("SELECT COUNT(1) FROM $from WHERE $where", $params);

        $headers = [
            get_string('report_table_header_email', 'quizaccess_quilgo'),
            get_string('report_table_header_name', 'quizaccess_quilgo'),
            get_string('report_table_header_attempt', 'quizaccess_quilgo'),
            get_string('report_table_header_score', 'quizaccess_quilgo'),
            get_string('report_table_header_timefinish', 'quizaccess_quilgo'),
            get_string('report_table_header_time_taken', 'quizaccess_quilgo'),
            get_string('report_table_header_confidence_levels', 'quizaccess_quilgo'),
            get_string('report_table_header_proctoring_report', 'quizaccess_quilgo'),
            get_string('report_table_header_attempt_results', 'quizaccess_quilgo'),
        ];

        $columns = [
            'email',
            'userfullname',
            'attempt',
            'sumgrades',
            'timefinish',
            'timetakens',
            'confidence_level',
            'proctoring_report',
            'attempt_results',
        ];

        $this->define_baseurl($this->repurl->out(false));
        $this->define_headers($headers);
        $this->define_columns($columns);
        $this->sortable(true, 'timefinish', SORT_DESC);
        $this->no_sorting('proctoring_report');
        $this->no_sorting('attempt_results');
        $this->no_sorting('confidence_level');
        $this->is_collapsible = false;
    }

    /**
     * Sumgrades column formatting
     * @param mixed $value record row
     * @return mixed
     */
    public function col_sumgrades($value) {
        if (empty($value->sumgrades)) {
            return html_writer::tag(
                'span',
                get_string('report_table_row_notyetgraded', 'quizaccess_quilgo'),
                ['class' => 'text-muted']
            );
        }

        $quiz = $this->quizobj->get_quiz();
        $gradepct = format_float($value->sumgrades * 100 / $quiz->sumgrades, $quiz->decimalpoints, true, true);
        $textclass = "";

        if ($gradepct > 80) {
            $textclass = "text-success";
        } else if ($gradepct > 50 && $gradepct <= 80) {
            $textclass = "text-warning";
        } else {
            $textclass = "text-danger";
        }

        return html_writer::tag('span', "$gradepct%", ['class' => $textclass]);
    }

    /**
     * Time finish column formatting
     * @param  mixed $value record row
     * @return mixed
     */
    public function col_timefinish($value) {
        return userdate($value->timefinish, get_string('strftimerecent', 'langconfig'));
    }

    /**
     * Timetakens column formatting
     * @param mixed $value record row
     * @return mixed
     */
    public function col_timetakens($value) {
        $timetaken = $value->timefinish - $value->timestart;
        $quiz = $this->quizobj->get_quiz();

        if ($timetaken) {
            $caption = format_time($timetaken);
            $overtime = null;
            $textclass = "text-success";
            if ($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) {
                $overtime = $timetaken - $quiz->timelimit;
                $overtime = format_time($overtime);
                $textclass = "text-danger";
                $caption .= "<br/>" . get_string('report_table_row_overdue', 'quizaccess_quilgo', $overtime);
            }

            return html_writer::tag('span', $caption, ['class' => $textclass]);
        }

        return "-";
    }

    /**
     * Proctoring column formatting
     * @param mixed $value record row
     * @return mixed
     */
    public function col_proctoring_report($value) {
        global $OUTPUT;

        $caption = get_string('report_table_row_view_report', 'quizaccess_quilgo');
        $icon = html_writer::tag('i', '', ['class' => 'fa fa-bar-chart']);
        $attributes = [
            'id' => 'quilgo-report-detail',
            'data-attemptid' => $value->id,
            'data-cmid' => $this->cmid,
            'data-preview' => $value->preview,
            'class' => 'btn btn-outline-primary py-1',
            'style' => 'margin: -6px 0; white-space: nowrap;',
        ];

        return $OUTPUT->action_link('#', "$icon $caption", null, $attributes);
    }

    /**
     * Attempt column formatting
     * @param mixed $value record row
     * @return mixed
     */
    public function col_attempt_results($value) {
        global $OUTPUT;

        $content = html_writer::tag('i', '', ['class' => 'fa fa-external-link']);
        $url = new moodle_url('/mod/quiz/review.php', ['attempt' => $value->id]);
        $attributes = ['target' => '_blank'];

        return $OUTPUT->action_link($url, $content, null, $attributes);
    }

    /**
     * Confidence level column formatting
     * @param mixed $value record row
     * @return mixed
     */
    public function col_confidence_level($value) {
        $confidencelevelcaption = "";
        $generatestatus = $value->generate_status;
        $textclass = "text-muted";

        if (is_null($generatestatus)) {
            $confidencelevelcaption = get_string('report_table_row_stat_queued', 'quizaccess_quilgo');
        } else if ($generatestatus == QUIZACCESS_QUILGO_REPORT_STATUS_NOT_READY) {
            $confidencelevelcaption = get_string('report_table_row_stat_not_ready', 'quizaccess_quilgo');
        } else {
            $confidencelevel = quizaccess_quilgo_define_confidence_level($value->camera_enabled, json_decode($value->stat));
            $confidencelevelcaption = get_string('report_table_row_confidence_level_' . $confidencelevel, 'quizaccess_quilgo');

            if ($confidencelevel == QUIZACCESS_QUILGO_CONFIDENCE_LEVEL_HIGH) {
                $textclass = 'text-success';
            } else if ($confidencelevel == QUIZACCESS_QUILGO_CONFIDENCE_LEVEL_MODERATE) {
                $textclass = 'text-warning';
            } else {
                $textclass = 'text-danger';
            }
        }

        $attributes = [
            'class' => $textclass,
            'data-attemptid' => $value->id,
            'data-cmid' => $this->cmid,
            'id' => 'quilgo-report-stat',
            'data-statstatus' => is_null($generatestatus) ? QUIZACCESS_QUILGO_REPORT_STATUS_QUEUED : $generatestatus,
        ];

        return html_writer::tag('span', $confidencelevelcaption, $attributes);
    }

    /**
     * Handle show the table or empty proctoring report message
     *
     * @return mixed
     */
    public function show() {
        if (!$this->isrecordexists) {
            echo html_writer::tag('p', get_string('report_empty', 'quizaccess_quilgo'), ['class' => 'text-center']);
            return;
        }

        $buttonexporticon = html_writer::tag('i', '', ['class' => 'fa fa-download']);
        $buttonexporttext = html_writer::span(
            get_string('report_table_export_proctoring_data', 'quizaccess_quilgo'),
            'quilgo-export-csv-text'
        );
        $buttonexport = html_writer::tag(
            'button',
            $buttonexporticon . " " . $buttonexporttext,
            ['class' => 'btn btn-outline-success text-center quilgo-export-csv-btn']
        );
        $buttonexportcontainer = html_writer::div(
            $buttonexport,
            'd-flex justify-content-end'
        );

        $exportmsg = html_writer::div(
            get_string('report_table_export_csv_error', 'quizaccess_quilgo'),
            'd-flex justify-content-center alert alert-warning mt-3 quilgo-hidden quilgo-export-csv-msg'
        );

        echo html_writer::div(
            $buttonexportcontainer . $exportmsg,
            'd-flex flex-column mb-4'
        );

        $this->out($this->perpage, true);
    }
}
