<!DOCTYPE html>
<html>

<!-- TODO: when templating this, pre-populate the ignored shows value with something pulled from a config file -->

<head>
    <style>
        /* dark mode */
        body {
            background-color: #1e1e1e;
            color: white;
        }

        /* enable borders on the table row */
        table {
            border-collapse: collapse;
        }

        table td {
            padding-right: 5px;
        }

        /* remove top & bottom margins */
        .report-info *,
        .episode * {
            margin-bottom: 0;
            margin-top: 0;
        }

        /* visually separate the report header from the contents */
        .report-info .report {
            background-color: #0c3c55;
            border-radius: 7px;
            display: inline-block;
        }

        .report h3 {
            display: inline;
        }

        .report.stats {
            margin-top: 4px;
        }

        details {
            margin-bottom: 10px;
        }

        summary {
            cursor: pointer;
        }

        /* prevent the details from taking up the entire width of the screen */
        .show>details {
            max-width: 50%;
        }

        /* indent season headers some */
        .season {
            margin-left: 1em;
        }

        /* indent individual episode timestamps some more */
        .episode {
            margin-left: 1em;
        }

        /* if an intro was not found previously but is now, that's good */
        .episode[data-warning="improvement"] {
            background-color: #044b04;
        }

        /* if an intro was found previously but isn't now, that's bad */
        .episode[data-warning="only_previous"],
        .episode[data-warning="missing"] {
            background-color: firebrick;
        }

        /* if an intro was found on both runs but the timestamps are pretty different, that's interesting */
        .episode[data-warning="different"] {
            background-color: #b77600;
        }

        #stats.warning {
            border: 2px solid firebrick;
            font-weight: bolder;
        }
    </style>
</head>

<body>
    <div class="report-info">
        <h2 class="margin-bottom:1em">Intro Timestamp Differential</h2>

        <div class="report old">
            <h3 style="margin-top:0.5em">First report</h3>

            {{ block "ReportInfo" .OldReport }}
            <table>
                <tbody>
                    <tr style="border-bottom: 1px solid black">
                        <td>Path</td>
                        <td><code>{{ .Path }}</code></td>
                    </tr>

                    <tr>
                        <td>Jellyfin</td>
                        <td>{{ .ServerInfo.Version }} on {{ .ServerInfo.OperatingSystem }}</td>
                    </tr>
                    <tr>
                        <td>Analysis Settings</td>
                        <td>{{ printAnalysisSettings .PluginConfig }}</td>
                    </tr>
                    <tr style="border-bottom: 1px solid black">
                        <td>Introduction Requirements</td>
                        <td>{{ printIntroductionReqs .PluginConfig }}</td>
                    </tr>

                    <tr>
                        <td>Start time</td>
                        <td>{{ printTime .StartedAt }}</td>
                    </tr>
                    <tr>
                        <td>End time</td>
                        <td>{{ printTime .FinishedAt }}</td>
                    </tr>
                    <tr>
                        <td>Duration</td>
                        <td>{{ printDuration .Runtime }}</td>
                    </tr>
                </tbody>
            </table>
            {{ end }}
        </div>

        <div class="report new">
            <h3 style="padding-top:0.5em">Second report</h3>

            {{ template "ReportInfo" .NewReport }}
        </div>
        <br />

        <div class="report stats">
            <h3 style="padding-top:0.5em">Statistics</h3>

            <table>
                <tbody>
                    <tr>
                        <td>Total episodes</td>
                        <td id="statTotal"></td>
                    </tr>
                    <tr>
                        <td>Never found</td>
                        <td id="statMissing"></td>
                    </tr>
                    <tr>
                        <td>Changed</td>
                        <td id="statChanged"></td>
                    </tr>
                    <tr>
                        <td>Gains</td>
                        <td id="statGain"></td>
                    </tr>
                    <tr>
                        <td>Losses</td>
                        <td id="statLoss"></td>
                    </tr>
                </tbody>
            </table>
        </div>

        <div class="report settings">
            <h3 style="padding-top:0.5em">Settings</h3>

            <form style="display:table">
                <label for="minimumPercentage">Minimum percentage</label>
                <input id="minimumPercentage" type="number" value="85" min="0" max="100"
                    style="margin-left: 5px; max-width: 100px" /> <br />

                <label for="ignoreShows">Ignored shows</label>
                <input id="ignoredShows" type="text" /> <br />

                <button id="btnUpdate" type="button">Update</button>
            </form>
        </div>
    </div>

    {{/* store a reference to the data before the range query */}}
    {{ $p := . }}

    {{/* sort the show names and iterate over them */}}
    {{ range $name := sortShows .OldReport.Shows }}
    <div class="show" id="{{ $name }}">
        <details>
            {{/* get the unsorted seasons for this show */}}
            {{ $seasons := index $p.OldReport.Shows $name }}

            {{/* log the show name and number of seasons */}}
            <summary>
                <span class="showTitle">
                    <strong>{{ $name }}</strong>
                    <span id="stats"></span>
                </span>
            </summary>

            <div class="seasons">
                {{/* sort the seasons to ensure they display in numerical order */}}
                {{ range $seasonNumber := (sortSeasons $seasons) }}
                <div class="season" id="{{ $name }}-{{ $seasonNumber }}">
                    <details>
                        <summary>
                            <span>
                                <strong>Season {{ $seasonNumber }}</strong>
                                <span id="stats"></span>
                            </span>
                        </summary>

                        {{/* compare each episode in the old report to the same episode in the new report */}}
                        {{ range $episode := index $seasons $seasonNumber }}

                        {{/* lookup and compare both episodes */}}
                        {{ $comparison := compareEpisodes $episode.EpisodeId $p }}
                        {{ $old := $comparison.Old }}
                        {{ $new := $comparison.New }}

                        {{/* set attributes indicating if an intro was found in the old and new reports */}}
                        <div class="episode" data-warning="{{ $comparison.WarningShort }}">
                            <p>{{ $episode.Title }}</p>

                            <p>
                                Old: {{ $old.FormattedStart }} - {{ $old.FormattedEnd }}
                                (<span class="duration old">{{ $old.Duration }}</span>)
                                (valid: {{ $old.Valid }}) <br />

                                New: {{ $new.FormattedStart }} - {{ $new.FormattedEnd }}
                                (<span class="duration new">{{ $new.Duration }}</span>)
                                (valid: {{ $new.Valid }}) <br />

                                {{ if ne $comparison.WarningShort "okay" }}
                                Warning: {{ $comparison.Warning }}
                                {{ end }}
                            </p>

                            <br />
                        </div>
                        {{ end }}
                    </details>
                </div>
                {{ end }}
            </div>
        </details>
    </div>
    {{ end }}

    <script>
        function count(parent, warning) {
            const sel = `div.episode[data-warning='${warning}']`

            // Don't include hidden elements in the count
            let count = 0;
            for (const elem of parent.querySelectorAll(sel)) {
                // offsetParent is defined when the element is not hidden
                if (elem.offsetParent) {
                    count++;
                }
            }

            return count;
        }

        function getPercent(part, whole) {
            const percent = Math.round((part * 10_000) / whole) / 100;
            return `${part} (${percent}%)`;
        }

        function setText(selector, text) {
            document.querySelector(selector).textContent = text;
        }

        // Gets the minimum percentage of episodes in a group (a series or season)
        // that must have a detected introduction.
        function getMinimumPercentage() {
            const value = document.querySelector("#minimumPercentage").value;
            return Number(value);
        }

        // Gets the average duration for all episodes in a parent group.
        // durationClass must be either "old" or "new".
        function getAverageDuration(parent, durationClass) {
            // Get all durations in the parent
            const elems = parent.querySelectorAll(".duration." + durationClass);

            // Calculate the average duration, ignoring any episode without an intro
            let totalDuration = 0;
            let totalEpisodes = 0;
            for (const e of elems) {
                const dur = Number(e.textContent);
                if (dur === 0) {
                    continue;
                }

                totalDuration += dur;
                totalEpisodes++;
            }

            if (totalEpisodes === 0) {
                return 0;
            }

            return Math.round(totalDuration / totalEpisodes);
        }

        // Calculate statistics for all episodes in a parent element (a series or a season).
        function setGroupStatistics(parent) {
            // Count the total number of episodes.
            const total = parent.querySelectorAll("div.episode").length;

            // Count how many episodes have no warnings.
            const okayCount = count(parent, "okay") + count(parent, "improvement");
            const okayPercent = Math.round((okayCount * 100) / total);
            const isOkay = okayPercent >= getMinimumPercentage();

            // Calculate the previous and current average durations
            const oldDuration = getAverageDuration(parent, "old");
            const newDuration = getAverageDuration(parent, "new");

            // Display the statistics
            const stats = parent.querySelector("#stats");
            stats.textContent = `${okayCount} / ${total} (${okayPercent}%) okay. r1 ${oldDuration} r2 ${newDuration}`;

            if (!isOkay) {
                stats.classList.add("warning");
            } else {
                stats.classList.remove("warning");
            }
        }

        function updateGlobalStatistics() {
            // Display all shows
            for (const show of document.querySelectorAll("div.show")) {
                show.style.display = "unset";
            }

            // Hide any shows that are ignored
            for (let ignored of document.querySelector("#ignoredShows").value.split(",")) {
                const elem = document.querySelector(`div.show[id='${ignored}']`);
                if (!elem) {
                    console.warn("unable to find show", ignored);
                    continue;
                }

                elem.style.display = "none";
            }

            const total = document.querySelectorAll("div.episode").length;
            const missing = count(document, "missing");
            const different = count(document, "different")
            const gain = count(document, "improvement");
            const loss = count(document, "only_previous");
            const okay = total - missing - different - loss;

            setText("#statTotal", getPercent(okay, total));
            setText("#statMissing", getPercent(missing, total));
            setText("#statChanged", getPercent(different, total));
            setText("#statGain", getPercent(gain, total));
            setText("#statLoss", getPercent(loss, total));
        }

        function updateStatistics() {
            for (const series of document.querySelectorAll("div.show")) {
                setGroupStatistics(series);

                for (const season of series.querySelectorAll("div.season")) {
                    setGroupStatistics(season);
                }
            }
        }

        // Display statistics for all episodes and by groups
        updateGlobalStatistics();
        updateStatistics();

        // Add event handlers
        document.querySelector("#minimumPercentage").addEventListener("input", updateStatistics);
        document.querySelector("#btnUpdate").addEventListener("click", updateGlobalStatistics);
    </script>
</body>

</html>
