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

/**
 * This file contains the backend webservice contact functionality for the DTA plugin.
 *
 * @package   assignsubmission_dta
 * @copyright 2023 Your Name
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace assignsubmission_dta;

use assignsubmission_dta\dta_db_utils;
use assignsubmission_dta\dta_backend_utils;
use assignsubmission_dta\models\dta_result;
use assignsubmission_dta\models\dta_result_summary;
use assignsubmission_dta\models\dta_recommendation;

/**
 * Utility class for DTA submission plugin result display.
 *
 * @package   assignsubmission_dta
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class dta_view_submission_utils {

    /**
     * Broadly used in logic, parametrized for easier change.
     */
    public const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = 'assignsubmission_dta';

    /**
     * Generates a short summary HTML (like your old plugin).
     *
     * @param int $assignmentid The assignment ID.
     * @param int $submissionid The submission ID to create a report for.
     * @return string The HTML summary.
     */
    public static function assignsubmission_dta_generate_summary_html(
        int $assignmentid,
        int $submissionid
    ): string {
        // 1) Retrieve the summary data from the DB (adjust your DB-utils class as needed).
        $summary = dta_db_utils::assignsubmission_dta_get_result_summary_from_database($assignmentid, $submissionid);

        // 2) Prepare an HTML buffer.
        $html = '';

        // 3) Extract counts from your new method names.
        $unknowncount = $summary->assignsubmission_dta_unknown_count();
        $compilecount = $summary->assignsubmission_dta_compilation_error_count();
        $successcount = $summary->assignsubmission_dta_successful_count();
        $failcount    = $summary->assignsubmission_dta_failed_count();
        $totalcount   = $summary->assignsubmission_dta_result_count();

        // 4) Compute success rate if no unknown/compile errors and total>0.
        $successrate = '?';
        if ($unknowncount === 0 && $compilecount === 0 && $totalcount > 0) {
            $successrate = round(($successcount / $totalcount) * 100, 2);
        }

        // 5) "X/Y (Z%) tests successful" line:
        // If either compile errors or unknown exist -> show "?", else X/Y (rate%).
        $html .= $successcount . '/';
        if ($compilecount === 0 && $unknowncount === 0) {
            $html .= ($totalcount > 0)
                ? ($totalcount . ' (' . $successrate . '%)')
                : ('0 (' . $successrate . ')');
        } else {
            $html .= '?';
        }
        $html .= get_string('tests_successful', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME) . "<br />";

        // 6) If there are compilation errors, show them.
        if ($compilecount > 0) {
            $html .= $compilecount
                  . get_string('compilation_errors', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
                  . "<br />";
        }

        // 7) If there are unknown results, show them.
        if ($unknowncount > 0) {
            $html .= $unknowncount
                  . get_string('unknown_state', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
                  . "<br />";
        }

        // If there are failed tests, show them.
        if ($failcount > 0) {
            $html .= $failcount
                  . get_string('failures', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
                  . "<br />";
        }

        // 8) Competencies (like your old snippet).
        $showncompetencies   = explode(';', $summary->successfultestcompetencies);
        $overallcompetencies = explode(';', $summary->overalltestcompetencies);

        $tmp  = '';
        $size = count($showncompetencies);
        for ($i = 0; $i < $size; $i++) {
            $shown = $showncompetencies[$i];
            $comp  = $overallcompetencies[$i];

            // If the competency was actually used (non-zero?), show a row.
            if ($shown !== '0') {
                $shownval = (float) $shown;
                $compval  = (float) $comp;

                // Guard division by zero.
                $pct = 0;
                if ($compval > 0) {
                    $pct = 100.0 * $shownval / $compval;
                }

                // "compX XX%<br />"
                $tmp .= get_string('comp' . $i, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
                    . ' ' . round($pct, 2) . '%<br />';
            }
        }

        $html .= get_string('success_competencies', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            . "<br />" . $tmp . "<br />";

        // 9) Wrap it in a DIV for styling, and return.
        return \html_writer::div($html, 'dtaSubmissionSummary');
    }

    /**
     * Generates detailed view HTML.
     *
     * @param int $assignmentid The assignment ID.
     * @param int $submissionid The submission to create a report for.
     * @return string HTML detail view.
     */
    public static function assignsubmission_dta_generate_detail_html(
        int $assignmentid,
        int $submissionid
    ): string {
        // Fetch data.
        $summary = dta_db_utils::assignsubmission_dta_get_result_summary_from_database(
            $assignmentid,
            $submissionid
        );
        $recommendations = dta_db_utils::assignsubmission_dta_get_recommendations_from_database(
            $assignmentid,
            $submissionid
        );

        $html = '';

        // Summary table.
        $tableheaderrowattributes = ['class' => 'dtaTableHeaderRow'];
        $tablerowattributes       = ['class' => 'dtaTableRow'];
        $resultrowattributes      = $tablerowattributes;
        $unknownattributes        = 'dtaResultUnknown';
        $successattributes        = 'dtaResultSuccess';
        $failureattributes        = 'dtaResultFailure';
        $compilationerrorattributes = 'dtaResultCompilationError';
        $attributes               = ['class' => 'dtaTableData'];

        // Build the summary table header.
        $tmp = \html_writer::tag(
            'th',
            get_string('summary', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            ['class' => 'dtaTableHeader']
        );
        $tmp .= \html_writer::empty_tag('th', ['class' => 'dtaTableHeader']);
        $header = \html_writer::tag('tr', $tmp, $tableheaderrowattributes);
        $header = \html_writer::tag('thead', $header);

        $body = '';

        // Pull the counters from the summary object.
        $resultcount      = $summary->assignsubmission_dta_result_count();
        $successfulcount  = $summary->assignsubmission_dta_successful_count();
        $failedcount      = $summary->assignsubmission_dta_failed_count();
        $compilationcount = $summary->assignsubmission_dta_compilation_error_count();
        $unknowncount     = $summary->assignsubmission_dta_unknown_count();

        // Total items.
        $tmp = \html_writer::tag(
            'td',
            get_string('total_items', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
        $tmp .= \html_writer::tag('td', $resultcount, $attributes);
        $resultrowattributes = $tablerowattributes;
        // Original code colors this row as unknown by default.
        $resultrowattributes['class'] .= ' ' . $unknownattributes;
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Tests successful.
        $tmp = \html_writer::tag(
            'td',
            get_string('tests_successful', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
        $tmp .= \html_writer::tag('td', $successfulcount, $attributes);
        $resultrowattributes = $tablerowattributes;

        // Compute success rate if no unknown or compilation errors, and resultcount > 0.
        $successrate = '?';
        if ($unknowncount == 0 && $compilationcount == 0 && $resultcount > 0) {
            $successrate = round(($successfulcount / $resultcount) * 100, 2);
            if ($successrate < 50) {
                $resultrowattributes['class'] .= ' ' . $compilationerrorattributes;
            } else if ($successrate < 75) {
                $resultrowattributes['class'] .= ' ' . $failureattributes;
            } else {
                $resultrowattributes['class'] .= ' ' . $successattributes;
            }
        } else {
            // If unknown or compilation errors => highlight as unknown.
            $resultrowattributes['class'] .= ' ' . $unknownattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Failures.
        $tmp = \html_writer::tag(
            'td',
            get_string('failures', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
        $tmp .= \html_writer::tag('td', $failedcount, $attributes);
        $resultrowattributes = $tablerowattributes;
        if ($failedcount > 0) {
            $resultrowattributes['class'] .= ' ' . $failureattributes;
        } else {
            $resultrowattributes['class'] .= ' ' . $successattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Compilation errors.
        $tmp = \html_writer::tag(
            'td',
            get_string('compilation_errors', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
        $tmp .= \html_writer::tag('td', $compilationcount, $attributes);
        $resultrowattributes = $tablerowattributes;
        if ($compilationcount > 0) {
            $resultrowattributes['class'] .= ' ' . $compilationerrorattributes;
        } else {
            $resultrowattributes['class'] .= ' ' . $successattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Unknown state.
        $tmp = \html_writer::tag(
            'td',
            get_string('unknown_state', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
        $tmp .= \html_writer::tag('td', $unknowncount, $attributes);
        $resultrowattributes = $tablerowattributes;
        if ($unknowncount > 0) {
            $resultrowattributes['class'] .= ' ' . $unknownattributes;
        } else {
            $resultrowattributes['class'] .= ' ' . $successattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Success rate row.
        $tmp = \html_writer::tag(
            'td',
            \html_writer::tag('b', get_string('success_rate', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)),
            $attributes
        );
        // If no compilation errors or unknown => show successrate, else "?".
        $suffix = ($compilationcount == 0 && $unknowncount == 0 && $resultcount > 0)
            ? ($resultcount . ' (' . $successrate . '%)')
            : '?';
        $tmp .= \html_writer::tag(
            'td',
            \html_writer::tag('b', $successfulcount . '/' . $suffix),
            $attributes
        );
        $resultrowattributes = $tablerowattributes;
        if ($compilationcount == 0 && $unknowncount == 0 && $resultcount > 0) {
            if ($successrate !== '?' && $successrate < 50) {
                $resultrowattributes['class'] .= ' ' . $compilationerrorattributes;
            } else if ($successrate !== '?' && $successrate < 75) {
                $resultrowattributes['class'] .= ' ' . $failureattributes;
            } else {
                $resultrowattributes['class'] .= ' ' . $successattributes;
            }
        } else {
            $resultrowattributes['class'] .= ' ' . $unknownattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Finalize the summary table.
        $body  = \html_writer::tag('tbody', $body);
        $table = \html_writer::tag('table', $header . $body, ['class' => 'dtaTable']);
        $html .= $table;

        // Spacing after the summary table.
        $html .= \html_writer::empty_tag('div', ['class' => 'dtaSpacer']);

        // Recommendations table.
        if (!empty($recommendations)) {
            $allowedsortfields = ['topic', 'exercise_name', 'difficulty', 'score'];
            $allowedsortdirs   = ['asc', 'desc'];

            // Make sure only one space before ??
            $sortby  = $_POST['sortby'] ?? 'score';
            $sortdir = $_POST['sortdir'] ?? 'asc';

            if (!in_array($sortby, $allowedsortfields)) {
                $sortby = 'score';
            }
            if (!in_array($sortdir, $allowedsortdirs)) {
                $sortdir = 'asc';
            }

            usort($recommendations, function ($a, $b) use ($sortby, $sortdir) {
                $valuea = $a->{$sortby};
                $valueb = $b->{$sortby};

                if (is_numeric($valuea) && is_numeric($valueb)) {
                    $comparison = $valuea - $valueb;
                } else {
                    $comparison = strnatcasecmp($valuea, $valueb);
                }

                if ($comparison === 0) {
                    return 0;
                }
                if ($sortdir === 'asc') {
                    return ($comparison < 0) ? -1 : 1;
                } else {
                    return ($comparison < 0) ? 1 : -1;
                }
            });

            $html .= \html_writer::tag(
                'h3',
                get_string('recommendations', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );

            $generatesortableheader = function ($columnname, $displayname) use ($sortby, $sortdir) {
                $newsortdir = ($sortby === $columnname && $sortdir === 'asc') ? 'desc' : 'asc';
                $class = 'dtaTableHeader';
                if ($sortby === $columnname) {
                    $class .= ' sorted ' . $sortdir;
                }

                // Sort button.
                $button = \html_writer::empty_tag('input', [
                    'type'  => 'submit',
                    'name'  => 'sortbutton',
                    'value' => ($newsortdir === 'asc' ? '↑' : '↓'),
                    'class' => 'sort-button',
                ]);

                // Hidden inputs.
                $hiddeninputs  = \html_writer::empty_tag('input', [
                    'type'  => 'hidden',
                    'name'  => 'sortby',
                    'value' => $columnname,
                ]);
                $hiddeninputs .= \html_writer::empty_tag('input', [
                    'type'  => 'hidden',
                    'name'  => 'sortdir',
                    'value' => $newsortdir,
                ]);

                $form  = \html_writer::start_tag('form', [
                    'method' => 'post',
                    'style'  => 'display:inline',
                ]);
                $form .= $hiddeninputs;
                $form .= $displayname . ' ' . $button;
                $form .= \html_writer::end_tag('form');

                return \html_writer::tag('th', $form, ['class' => $class]);
            };

            // Build the recommendations table header.
            $tableheader = '';
            $tableheader .= $generatesortableheader(
                'topic',
                get_string('topic', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );
            $tableheader .= $generatesortableheader(
                'exercise_name',
                get_string('exercise_name', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );
            $tableheader .= \html_writer::tag(
                'th',
                get_string('url', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                ['class' => 'dtaTableHeader']
            );
            $tableheader .= $generatesortableheader(
                'difficulty',
                get_string('difficulty', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );
            $tableheader .= $generatesortableheader(
                'score',
                get_string('score', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );

            $tableheader = \html_writer::tag('tr', $tableheader, ['class' => 'dtaTableHeaderRow']);
            $tableheader = \html_writer::tag('thead', $tableheader);

            // Table body for recommendations.
            $tablebody = '';
            foreach ($recommendations as $recommendation) {
                $row = '';
                $row .= \html_writer::tag('td', $recommendation->topic, $attributes);
                $row .= \html_writer::tag('td', $recommendation->exercise_name, $attributes);
                $row .= \html_writer::tag(
                    'td',
                    \html_writer::link($recommendation->url, $recommendation->url),
                    $attributes
                );
                $row .= \html_writer::tag('td', $recommendation->difficulty, $attributes);
                $row .= \html_writer::tag('td', $recommendation->score, $attributes);

                $tablebody .= \html_writer::tag('tr', $row, $tablerowattributes);
            }
            $tablebody = \html_writer::tag('tbody', $tablebody);

            $html .= \html_writer::tag('table', $tableheader . $tablebody, ['class' => 'dtaTable']);

            // Spacing after recommendations.
            $html .= \html_writer::empty_tag('div', ['class' => 'dtaSpacer']);
        }

        // Competency assessment table.
        $body  = '';
        $tmp   = \html_writer::tag(
            'th',
            get_string('competencies', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            ['class' => 'dtaTableHeader']
        );
        $tmp  .= \html_writer::empty_tag('th', ['class' => 'dtaTableHeader']);
        $header = \html_writer::tag('tr', $tmp, $tableheaderrowattributes);
        $header = \html_writer::tag('thead', $header);

        $showncompetencies   = explode(';', $summary->successfultestcompetencies);
        $overallcompetencies = explode(';', $summary->overalltestcompetencies);

        for ($index = 0, $size = count($overallcompetencies); $index < $size; $index++) {
            $comp  = $overallcompetencies[$index];
            $shown = $showncompetencies[$index];

            // If the competency was actually assessed, add a row.
            if ($comp !== '0') {
                $compval  = (float) $comp;
                $shownval = (float) $shown;

                // Guard division by zero.
                $pct = 0;
                if ($compval > 0) {
                    $pct = (100.0 * $shownval / $compval);
                }

                $resultrowattributes = $tablerowattributes;
                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('comp' . $index, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $resultrowattributes
                );
                $tmp .= \html_writer::tag(
                    'td',
                    round($pct, 2) . '% (' . $shown . ' / ' . $comp . ')',
                    $resultrowattributes
                );
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('comp_expl' . $index, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $resultrowattributes
                );
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
            }
        }
        $body   = \html_writer::tag('tbody', $body);
        $html  .= \html_writer::tag('table', $header . $body, ['class' => 'dtaTable']);

        // Add empty div for spacing.
        $html .= \html_writer::empty_tag('div', ['class' => 'dtaSpacer']);

        // Details table.
        $tmp = '';
        $tmp .= \html_writer::tag(
            'th',
            get_string('details', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            ['class' => 'dtaTableHeader']
        );
        $tmp .= \html_writer::empty_tag('th', ['class' => 'dtaTableHeader']);
        $header = \html_writer::tag('tr', $tmp, $tableheaderrowattributes);
        $header = \html_writer::tag('thead', $header);

        $body      = '';
        $spacerrow = null;
        foreach ($summary->results as $r) {
            // Add spacer row before each new entry (after the first).
            if (!is_null($spacerrow)) {
                $body .= $spacerrow;
            }

            $resultrowattributes = $tablerowattributes;

            // Set CSS class for colored left-border according to results state.
            if ($r->state === 0) {
                $resultrowattributes['class'] .= ' dtaResultUnknown';
            } else if ($r->state === 1) {
                $resultrowattributes['class'] .= ' dtaResultSuccess';
            } else if ($r->state === 2) {
                $resultrowattributes['class'] .= ' dtaResultFailure';
            } else if ($r->state === 3) {
                $resultrowattributes['class'] .= ' dtaResultCompilationError';
            }

            $tmp = '';
            $tmp .= \html_writer::tag(
                'td',
                get_string('package_name', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag('td', $r->packagename, $attributes);
            $tmp .= \html_writer::tag(
                'td',
                get_string('unit_name', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag('td', $r->classname, $attributes);
            $tmp .= \html_writer::tag(
                'td',
                get_string('test_name', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag('td', $r->name, $attributes);
            $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

            $tmp = '';
            $tmp .= \html_writer::tag(
                'td',
                get_string('status', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag(
                'td',
                dta_result::assignsubmission_dta_get_statename($r->state),
                $attributes
            );
            $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

            // If state != 1 (not successful), show additional info.
            if ($r->state !== 1) {
                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('failure_type', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $attributes
                );
                $tmp .= \html_writer::tag('td', $r->failureType, $attributes);
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('failure_reason', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $attributes
                );
                $tmp .= \html_writer::tag('td', $r->failureReason, $attributes);
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

                if (!is_null($r->lineNumber) && $r->lineNumber > 0) {
                    $tmp = '';
                    $tmp .= \html_writer::tag(
                        'td',
                        get_string('line_no', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                        $attributes
                    );
                    $tmp .= \html_writer::tag('td', $r->lineNumber, $attributes);
                    $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
                }

                if (!is_null($r->columnNumber) && $r->columnNumber > 0) {
                    $tmp = '';
                    $tmp .= \html_writer::tag(
                        'td',
                        get_string('col_no', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                        $attributes
                    );
                    $tmp .= \html_writer::tag('td', $r->columnNumber, $attributes);
                    $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
                }

                if (!is_null($r->position) && $r->position > 0) {
                    $tmp = '';
                    $tmp .= \html_writer::tag(
                        'td',
                        get_string('pos', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                        $attributes
                    );
                    $tmp .= \html_writer::tag('td', $r->position, $attributes);
                    $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
                }

                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('stacktrace', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $attributes
                );
                $tmp .= \html_writer::tag(
                    'td',
                    \html_writer::tag('details', $r->stacktrace, ['class' => 'dtaStacktraceDetails']),
                    $attributes
                );
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
            }

            if (is_null($spacerrow)) {
                // Reuse this spacer row between subsequent items.
                $spacerrow = \html_writer::empty_tag('tr', ['class' => 'dtaTableSpacer']);
            }
        }

        $html .= \html_writer::tag('table', $header . $body, ['class' => 'dtaTable']);

        // Wrap generated HTML into final div.
        $html = \html_writer::div($html, 'dtaSubmissionDetails');

        return $html;
    }
}