<?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 mod_lti\reportbuilder\local\systemreports;

use core\output\html_writer;
use core_reportbuilder\local\helpers\database;
use core_reportbuilder\local\report\column;
use mod_lti\reportbuilder\local\entities\tool_types;
use core_reportbuilder\system_report;

/**
 * Course external tools list system report class implementation.
 *
 * @package    mod_lti
 * @copyright  2023 Jake Dallimore <jrhdallimore@gmail.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class course_external_tools_list extends system_report {

    /** @var \stdClass the course to constrain the report to. */
    protected \stdClass $course;

    /** @var int the usage count for the tool represented in a row, and set by row_callback(). */
    protected int $perrowtoolusage = 0;

    /**
     * Initialise report, we need to set the main table, load our entities and set columns/filters
     */
    protected function initialise(): void {
        global $DB, $CFG;
        require_once($CFG->dirroot . '/mod/lti/locallib.php');

        $this->course = get_course($this->get_context()->instanceid);

        // Our main entity, it contains all the column definitions that we need.
        $entitymain = new tool_types();
        $entitymainalias = $entitymain->get_table_alias('lti_types');

        $this->set_main_table('lti_types', $entitymainalias);
        $this->add_entity($entitymain);

        // Now we can call our helper methods to add the content we want to include in the report.
        $this->add_columns($entitymain);
        $this->add_filters();
        $this->add_actions();

        // We need id and course in the actions column, without entity prefixes, so add these here.
        // We also need access to the tool usage count in a few places (the usage column as well as the actions column).
        $ti = database::generate_param_name(); // Tool instance param.
        $this->add_base_fields("{$entitymainalias}.id, {$entitymainalias}.course, ".
            "(SELECT COUNT($ti.id)
                FROM {lti} $ti
                WHERE $ti.typeid = {$entitymainalias}.id) AS toolusage");

        // Join the types_categories table, to include only tools available to the current course's category.
        $cattablealias = database::generate_alias();
        $joinsql = "LEFT JOIN {lti_types_categories} {$cattablealias}
                           ON ({$cattablealias}.typeid = {$entitymainalias}.id)";
        $this->add_join($joinsql);

        // Scope the report to the course context and include only those tools available to the category.
        $paramprefix = database::generate_param_name();
        $coursevisibleparam = database::generate_param_name();
        $categoryparam = database::generate_param_name();
        $toolstateparam = database::generate_param_name();
        [$insql, $params] = $DB->get_in_or_equal([get_site()->id, $this->course->id], SQL_PARAMS_NAMED, "{$paramprefix}_");
        $wheresql = "{$entitymainalias}.course {$insql} ".
            "AND {$entitymainalias}.coursevisible NOT IN (:{$coursevisibleparam}) ".
            "AND ({$cattablealias}.id IS NULL OR {$cattablealias}.categoryid = :{$categoryparam}) ".
            "AND {$entitymainalias}.state = :{$toolstateparam}";
        $params = array_merge(
            $params,
            [
                $coursevisibleparam => LTI_COURSEVISIBLE_NO,
                $categoryparam => $this->course->category,
                $toolstateparam => LTI_TOOL_STATE_CONFIGURED
            ]
        );
        $this->add_base_condition_sql($wheresql, $params);

        $this->set_downloadable(false, get_string('pluginname', 'mod_lti'));
        $this->set_default_per_page(10);
        $this->set_default_no_results_notice(null);
    }

    /**
     * Validates access to view this report
     *
     * @return bool
     */
    protected function can_view(): bool {
        return has_capability('mod/lti:addpreconfiguredinstance', $this->get_context());
    }

    public function row_callback(\stdClass $row): void {
        $this->perrowtoolusage = $row->toolusage;
    }

    /**
     * Adds the columns we want to display in the report.
     *
     * They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
     * unique identifier
     * @param tool_types $tooltypesentity
     * @return void
     */
    protected function add_columns(tool_types $tooltypesentity): void {
        $entitymainalias = $tooltypesentity->get_table_alias('lti_types');

        $columns = [
            'tool_types:name',
            'tool_types:description',
        ];

        $this->add_columns_from_entities($columns);

        // Tool usage column using a custom SQL subquery (defined in initialise method) to count tool instances within the course.
        // TODO: This should be replaced with proper column aggregation once that's added to system_report instances in MDL-76392.
        $this->add_column(new column(
            'usage',
            new \lang_string('usage', 'mod_lti'),
            $tooltypesentity->get_entity_name()
        ))
            ->set_type(column::TYPE_INTEGER)
            ->set_is_sortable(true)
            ->add_field("{$entitymainalias}.id")
            ->add_callback(fn() => $this->perrowtoolusage);

        // Enable toggle column.
        $this->add_column((new column(
            'showinactivitychooser',
            new \lang_string('showinactivitychooser', 'mod_lti'),
            $tooltypesentity->get_entity_name()
        ))
            // Site tools can be overridden on course level.
            ->add_join("LEFT JOIN {lti_coursevisible} lc ON lc.typeid = {$entitymainalias}.id AND lc.courseid = " . $this->course->id)
            ->set_type(column::TYPE_INTEGER)
            ->add_fields("{$entitymainalias}.id, {$entitymainalias}.coursevisible, lc.coursevisible as coursevisibleoverridden")
            ->set_is_sortable(false)
            ->set_callback(function(int $id, \stdClass $row): string {
                global $PAGE;
                $coursevisible = $row->coursevisible;
                $courseid = $this->course->id;
                if (!empty($row->coursevisibleoverridden)) {
                    $coursevisible = $row->coursevisibleoverridden;
                }

                if ($coursevisible == LTI_COURSEVISIBLE_ACTIVITYCHOOSER) {
                    $coursevisible = true;
                } else {
                    $coursevisible = false;
                }

                $renderer = $PAGE->get_renderer('core_reportbuilder');
                $attributes = [
                    ['name' => 'id', 'value' => $row->id],
                    ['name' => 'courseid', 'value' => $courseid],
                    ['name' => 'action', 'value' => 'showinactivitychooser-toggle'],
                    ['name' => 'state', 'value' => $coursevisible],
                ];
                $label = $coursevisible ? get_string('dontshowinactivitychooser', 'mod_lti')
                    : get_string('showinactivitychooser', 'mod_lti');

                $disabled = !has_capability('mod/lti:addcoursetool', \context_course::instance($courseid));

                return $renderer->render_from_template('core/toggle', [
                    'id' => 'showinactivitychooser-toggle-' . $row->id,
                    'checked' => $coursevisible,
                    'disabled' => $disabled,
                    'dataattributes' => $attributes,
                    'label' => $label,
                    'labelclasses' => 'visually-hidden',
                ]);
            })
        );

        // Attempt to create a dummy actions column, working around the limitations of the official actions feature.
        $this->add_column(new column(
            'actions', new \lang_string('actions'),
            $tooltypesentity->get_entity_name()
        ))
            ->set_type(column::TYPE_TEXT)
            ->set_is_sortable(false)
            ->add_fields("{$entitymainalias}.id, {$entitymainalias}.course, {$entitymainalias}.name")
            ->add_callback(function($field, $row) {
                global $OUTPUT;

                // Lock actions for site-level preconfigured tools.
                if (get_site()->id == $row->course) {
                    return \html_writer::div(
                        \html_writer::div(
                            $OUTPUT->pix_icon('t/locked', get_string('courseexternaltoolsnoeditpermissions', 'mod_lti')
                        ), 'tool-action-icon-container'), 'd-flex justify-content-end'
                    );
                }

                // Lock actions when the user can't add course tools.
                if (!has_capability('mod/lti:addcoursetool', \context_course::instance($row->course))) {
                    return \html_writer::div(
                        \html_writer::div(
                            $OUTPUT->pix_icon('t/locked', get_string('courseexternaltoolsnoeditpermissions', 'mod_lti')
                        ), 'tool-action-icon-container'), 'd-flex justify-content-end'
                    );
                }

                // Build and display an action menu.
                $menu = new \action_menu();
                $triggerlabel = get_string('actions');
                $visuallyhiddenlabel = html_writer::span($triggerlabel, 'visually-hidden d-inline-block');
                $menu->set_menu_trigger($OUTPUT->pix_icon('i/moremenu', '') . $visuallyhiddenlabel, 'btn btn-icon d-flex');
                $menu->triggerattributes['title'] = $triggerlabel;

                $menu->add(new \action_menu_link(
                    new \moodle_url('/mod/lti/coursetooledit.php', ['course' => $row->course, 'typeid' => $row->id]),
                    null,
                    get_string('edit', 'core'),
                    null
                ));

                $menu->add(new \action_menu_link(
                    new \moodle_url('#'),
                    null,
                    get_string('delete', 'core'),
                    null,
                    [
                        'data-action' => 'course-tool-delete',
                        'data-course-tool-id' => $row->id,
                        'data-course-tool-name' => $row->name,
                        'data-course-tool-usage' => $this->perrowtoolusage,
                        'class' => 'text-danger',
                    ],
                ));

                return $OUTPUT->render($menu);
            });

        // Default sorting.
        $this->set_initial_sort_column('tool_types:name', SORT_ASC);
    }

    /**
     * Add any actions for this report.
     *
     * @return void
     */
    protected function add_actions(): void {
    }

    /**
     * Adds the filters we want to display in the report
     *
     * They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
     * unique identifier
     */
    protected function add_filters(): void {

        $this->add_filters_from_entities([]);
    }
}
