{{!
    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/>.
}}
{{!
    @template local_thinkera/open_test

    «اختبار مفتوح»: the first unit's advanced exam for a visitor with no account. One template, four states told
    apart by flags: unavailable, intro (also shown with expired), attempt, result.

    The question HTML (`html`) and the lesson heading are already-rendered, already-escaped markup from the
    question engine and from open_test.php, so they are printed with triple braces on purpose.

    Example context (json):
    {
        "unavailable": false, "intro": true, "expired": false, "attempt": false, "result": false,
        "actionurl": "#", "ctaurl": "#", "loginurl": "#", "showlogin": true, "signedin": false,
        "perlesson": 5, "total": 20, "lessons": 4,
        "visiturl": "#", "visitid": 1, "visitsig": "abc",
        "mark": "14", "max": "20", "percent": 70, "tiermid": true,
        "sections": [{"heading": "الدرس 1-1: تطور تكنولوجيا المعلومات", "score": "3 من 5", "good": false,
            "questions": [{"number": 1, "html": "<div class=\"que\">…</div>"}]}]
    }
}}
<div class="tkc tkot">

{{#unavailable}}
    <section class="tkc-hero">
        <h2 class="tkc-title">{{#str}}ot_title, local_thinkera{{/str}}</h2>
        <p class="tkc-lead">{{#str}}ot_unavailable, local_thinkera{{/str}}</p>
    </section>
{{/unavailable}}

{{^unavailable}}

{{! ----------------------------------------------------------------------------------- introduction }}
{{#intro}}
    <section class="tkc-hero">
        <p class="tkc-kicker">{{#str}}ot_kicker, local_thinkera{{/str}}</p>
        <h2 class="tkc-title">{{#str}}ot_title, local_thinkera{{/str}}</h2>
        <p class="tkc-lead">{{#str}}ot_lead, local_thinkera, {{lessons}}{{/str}}</p>
        <ul class="tkot-facts">
            <li class="tkot-fact">{{#str}}ot_fact_questions, local_thinkera, {{total}}{{/str}}</li>
            <li class="tkot-fact">{{#str}}ot_fact_essays, local_thinkera, {{essaytotal}}{{/str}}</li>
            <li class="tkot-fact">{{#str}}ot_fact_level, local_thinkera{{/str}}</li>
            <li class="tkot-fact">{{#str}}ot_fact_open, local_thinkera{{/str}}</li>
            <li class="tkot-fact tkot-fact-time">⏱ {{#str}}ot_fact_minutes, local_thinkera, {{minutes}}{{/str}}</li>
        </ul>
        {{#expired}}<p class="tkot-expired" role="alert">{{#str}}ot_expired, local_thinkera{{/str}}</p>{{/expired}}
        {{! a POST, not a link: a crawler or a link preview that follows a GET must not draw a test. The action
            carries the edition (?edition=en), so no hidden field is needed for it. }}
        <form method="post" action="{{actionurl}}" class="tkot-lead" id="tkot-lead">
            <input type="hidden" name="begin" value="1">
            <input type="hidden" name="utm_source" value="{{source}}">
            <div class="tkot-fields">
                <label class="tkot-field tkot-field-wide">
                    <span class="tkot-field-label">{{#str}}ot_f_name, local_thinkera{{/str}}</span>
                    <input type="text" name="name" value="{{name}}" required maxlength="100" dir="auto"
                           autocomplete="name" {{#error}}aria-invalid="true" aria-describedby="tkot-error"{{/error}}>
                </label>
                <label class="tkot-field">
                    <span class="tkot-field-label">{{#str}}ot_f_email, local_thinkera{{/str}}</span>
                    <input type="email" name="email" value="{{email}}" required maxlength="254" dir="ltr"
                           autocomplete="email" inputmode="email" placeholder="name@example.com"
                           {{#error}}aria-invalid="true" aria-describedby="tkot-error"{{/error}}>
                </label>
                <label class="tkot-field">
                    <span class="tkot-field-label">{{#str}}ot_f_mobile, local_thinkera{{/str}}</span>
                    <input type="tel" name="mobile" value="{{mobile}}" required maxlength="30" dir="ltr"
                           autocomplete="tel" inputmode="tel" placeholder="01012345678"
                           {{#error}}aria-invalid="true" aria-describedby="tkot-error"{{/error}}>
                </label>
            </div>
            {{! out of sight and out of the tab order: a person never fills it, a script that fills every input does }}
            <div class="tkot-hp" aria-hidden="true">
                <label>Website <input type="text" name="website" value="" tabindex="-1" autocomplete="off"></label>
            </div>
            {{#error}}<p class="tkot-error" id="tkot-error" role="alert">{{error}}</p>{{/error}}
            <div class="tkc-hero-actions">
                <button type="submit" class="tk-btn tk-btn-primary tk-btn-lg">{{#str}}ot_start, local_thinkera{{/str}}</button>
            </div>
        </form>
        <p class="tkot-note">{{#str}}ot_timer_note, local_thinkera, {{minutes}}{{/str}} {{#str}}ot_note, local_thinkera{{/str}}</p>
        <p class="tkot-note">{{#str}}ot_consent, local_thinkera{{/str}}</p>
    </section>
{{/intro}}

{{! ----------------------------------------------------------------------------------- the questions }}
{{#attempt}}
    {{! The countdown. The server says how many seconds are left and enforces them; this only shows them. It stays
        at the top while the questions scroll under it, turns amber at five minutes and red at one, and hands the
        test in by itself at zero. The digits are isolated: «39:59» must not be turned around by a right-to-left page. }}
    <div class="tkot-timer" id="tkot-timer" role="timer" data-left="{{timeleft}}" data-total="{{timetotal}}"
         data-say5="{{#str}}ot_timer_5, local_thinkera{{/str}}" data-say1="{{#str}}ot_timer_1, local_thinkera{{/str}}"
         data-sayup="{{#str}}ot_timer_up, local_thinkera{{/str}}">
        <div class="tkot-timer-row">
            <span class="tkot-timer-label">⏱ {{#str}}ot_timer_label, local_thinkera{{/str}}</span>
            <span class="tkot-timer-clock" dir="ltr">{{timeclock}}</span>
        </div>
        <div class="tkot-timer-bar" aria-hidden="true"><span class="tkot-timer-fill"></span></div>
        <span class="tkot-timer-say visually-hidden" aria-live="assertive"></span>
    </div>
    <form method="post" action="{{visiturl}}" class="tkot-form" id="tkot-form">
        <input type="hidden" name="u" value="{{visitid}}">
        <input type="hidden" name="s" value="{{visitsig}}">
        <input type="hidden" name="finish" value="1">
        <input type="hidden" name="timeout" value="0" id="tkot-timeout">
        {{#sections}}
        <section class="tkot-lesson">
            <h3 class="tkot-lesson-title"><span class="tkot-lesson-name">{{{heading}}}</span></h3>
            {{#questions}}
            <div class="tkot-q{{#isessay}} tkot-q-essay{{/isessay}}" id="tkot-q{{number}}">
                {{#isessay}}<p class="tkot-essay-tag">{{#str}}ot_essay_tag, local_thinkera, {{marks}}{{/str}}</p>{{/isessay}}
                {{{html}}}
                {{! a plain box under the field names the question engine reads: its own editor needs an account }}
                {{#field}}
                <div class="tkot-essay-box">
                    <label for="tkot-ans{{number}}" class="tkot-field-label">{{label}}</label>
                    <textarea id="tkot-ans{{number}}" name="{{name}}" rows="9" maxlength="{{maxlength}}" dir="auto"></textarea>
                    <input type="hidden" name="{{format}}" value="{{plain}}">
                    {{#hint}}<small class="tkot-hint">{{hint}}</small>{{/hint}}
                    <small class="tkot-hint">{{#str}}ot_essay_ai, local_thinkera{{/str}}</small>
                </div>
                {{/field}}
            </div>
            {{/questions}}
        </section>
        {{/sections}}
        <div class="tkot-submit">
            <p class="tkot-submit-help">{{#str}}ot_submit_help, local_thinkera{{/str}}</p>
            <button type="submit" class="tk-btn tk-btn-primary tk-btn-lg">{{#str}}ot_submit, local_thinkera{{/str}}</button>
        </div>
    </form>
{{/attempt}}

{{! ----------------------------------------------------------------------------------- the result }}
{{#result}}
    <section class="tkc-hero tkot-result" aria-live="polite">
        <p class="tkc-kicker">{{#str}}ot_result_kicker, local_thinkera{{/str}}</p>
        <h2 class="tkc-title tkot-score">{{#str}}ot_score, local_thinkera, {"mark": "{{mark}}", "max": "{{max}}"}{{/str}}
            <span class="tkot-percent"><bdi dir="ltr">{{percent}}%</bdi></span></h2>
        <p class="tkc-lead">
            {{#tierhigh}}{{#str}}ot_tier_high, local_thinkera{{/str}}{{/tierhigh}}
            {{#tiermid}}{{#str}}ot_tier_mid, local_thinkera{{/str}}{{/tiermid}}
            {{#tierlow}}{{#str}}ot_tier_low, local_thinkera{{/str}}{{/tierlow}}
        </p>
        {{#haspending}}<p class="tkot-note">{{#str}}ot_pending_note, local_thinkera, {{pendingcount}}{{/str}}</p>{{/haspending}}
    </section>

    {{! the essays are read one at a time, by the model, while this page is open: it says how far it has got and
        reloads itself when the last one is settled, so the marks and the feedback appear where the page already is }}
    {{#grading}}
    <section class="tkot-grading" id="tkot-grading" role="status" aria-live="polite"
             data-url="{{gradeurl}}" data-u="{{visitid}}" data-s="{{visitsig}}">
        <span class="tkot-spinner" aria-hidden="true"></span>
        <span class="tkot-grading-text">{{#str}}ot_grading_working, local_thinkera, {"done": {{gradedone}}, "total": {{gradetotal}}}{{/str}}</span>
        <span class="tkot-grading-fail" hidden>{{#str}}ot_grading_failed, local_thinkera{{/str}}</span>
    </section>
    {{/grading}}

    <section class="tkot-bylesson" aria-labelledby="tkot-bylesson-h">
        <h3 id="tkot-bylesson-h" class="tkot-h">{{#str}}ot_by_lesson, local_thinkera{{/str}}</h3>
        <ul class="tkot-lessonlist">
            {{#sections}}
            <li class="tkot-lessonrow{{#good}} is-good{{/good}}">
                <span class="tkot-lessonrow-name">{{{heading}}}</span>
                <span class="tkot-lessonrow-score">{{score}}{{#waiting}} <span class="tkot-waiting">+ {{#str}}ot_lesson_waiting, local_thinkera{{/str}}</span>{{/waiting}}</span>
            </li>
            {{/sections}}
        </ul>
    </section>

    <section class="tkot-cta">
        <h3 class="tkot-h">{{#str}}ot_cta_title, local_thinkera{{/str}}</h3>
        <p>{{#str}}ot_cta_lead, local_thinkera{{/str}}</p>
        <div class="tkot-cta-actions">
            <a class="tk-btn tk-btn-primary tk-btn-lg" href="{{ctaurl}}">
                {{#signedin}}{{#str}}ot_cta_open, local_thinkera{{/str}}{{/signedin}}{{^signedin}}{{#str}}signupfree, local_thinkera{{/str}}{{/signedin}}
            </a>
            {{#showlogin}}<a class="tk-btn tk-btn-quiet" href="{{loginurl}}">{{#str}}haveaccount, local_thinkera{{/str}}</a>{{/showlogin}}
        </div>
    </section>

    <section class="tkot-review" aria-labelledby="tkot-review-h">
        <h3 id="tkot-review-h" class="tkot-h">{{#str}}ot_review, local_thinkera{{/str}}</h3>
        {{#sections}}
        <section class="tkot-lesson">
            <h4 class="tkot-lesson-title"><span class="tkot-lesson-name">{{{heading}}}</span> <span class="tkot-lesson-score">{{score}}</span></h4>
            {{#questions}}
            <div class="tkot-q{{#isessay}} tkot-q-essay{{/isessay}}" id="tkot-q{{number}}">
                {{#isessay}}<p class="tkot-essay-tag">{{#str}}ot_essay_tag, local_thinkera, {{marks}}{{/str}}</p>{{/isessay}}
                {{{html}}}
                {{! what became of this essay: the tag the visitor reads, and the one the page's script rewrites }}
                {{#reading}}<p class="tkot-fate is-reading" data-fate="reading">{{#str}}ot_fate_reading, local_thinkera{{/str}}</p>{{/reading}}
                {{#pending}}<p class="tkot-fate is-pending">{{#str}}ot_fate_pending, local_thinkera{{/str}}</p>{{/pending}}
                {{#graded}}<p class="tkot-fate is-graded">{{#str}}ot_fate_graded, local_thinkera{{/str}}</p>{{/graded}}
                {{#empty}}<p class="tkot-fate is-empty">{{#str}}ot_fate_empty, local_thinkera{{/str}}</p>{{/empty}}
            </div>
            {{/questions}}
        </section>
        {{/sections}}
    </section>

    {{! the signed visit is all this carries: the details already given are read from the lead on the server }}
    <form method="post" action="{{actionurl}}" class="tkot-again">
        <input type="hidden" name="begin" value="1">
        <input type="hidden" name="again" value="1">
        <input type="hidden" name="u" value="{{visitid}}">
        <input type="hidden" name="s" value="{{visitsig}}">
        <button type="submit" class="tk-btn tk-btn-ghost">{{#str}}ot_again, local_thinkera{{/str}}</button>
    </form>
{{/result}}

{{/unavailable}}
</div>

{{#js}}
(function() {
    var el = document.getElementById('tkot-timer');
    var form = document.getElementById('tkot-form');
    if (!el || !form) {
        return;
    }
    var clock = el.querySelector('.tkot-timer-clock');
    var fill = el.querySelector('.tkot-timer-fill');
    var say = el.querySelector('.tkot-timer-say');
    var total = parseInt(el.getAttribute('data-total'), 10) || 1;
    // The deadline in this browser's own time, worked out from the server's count of what is left: a visitor
    // whose clock is an hour wrong sees the same forty minutes as everybody else.
    var end = Date.now() + (parseInt(el.getAttribute('data-left'), 10) || 0) * 1000;
    var said5 = false;
    var said1 = false;
    var sent = false;
    var pad = function(n) {
        return (n < 10 ? '0' : '') + n;
    };
    function tick() {
        var left = Math.max(0, Math.round((end - Date.now()) / 1000));
        var h = Math.floor(left / 3600);
        var m = Math.floor((left % 3600) / 60);
        clock.textContent = (h ? h + ':' + pad(m) : pad(m)) + ':' + pad(left % 60);
        fill.style.inlineSize = (100 * left / total) + '%';
        el.classList.toggle('is-warn', left <= 300 && left > 60);
        el.classList.toggle('is-danger', left <= 60);
        // said once each, not every second: a screen reader reading a clock aloud is noise
        if (left <= 300 && left > 60 && !said5) {
            said5 = true;
            say.textContent = el.getAttribute('data-say5');
        }
        if (left <= 60 && left > 0 && !said1) {
            said1 = true;
            say.textContent = el.getAttribute('data-say1');
        }
        if (left === 0 && !sent) {
            sent = true;
            el.classList.add('is-up');
            say.textContent = el.getAttribute('data-sayup');
            document.getElementById('tkot-timeout').value = '1';
            // submit() does not stop on an empty answer box: at zero the test goes in with whatever it holds
            form.submit();
            return;
        }
        if (!sent) {
            // a phone that slept wakes here, finds the time already gone, and hands in at once
            window.setTimeout(tick, 250);
        }
    }
    form.addEventListener('submit', function() {
        sent = true;
    });
    tick();
})();
{{/js}}

{{#js}}
(function() {
    var box = document.getElementById('tkot-grading');
    if (!box) {
        return;
    }
    var text = box.querySelector('.tkot-grading-text');
    var fail = box.querySelector('.tkot-grading-fail');
    var body = function() {
        var b = new URLSearchParams();
        b.set('u', box.getAttribute('data-u'));
        b.set('s', box.getAttribute('data-s'));
        return b;
    };
    var misses = 0;
    // One essay a request: the model takes tens of seconds over each, so a single long request would be
    // given up on by a phone. The server carries on even if this page goes away, so coming back finds the marks.
    function next() {
        fetch(box.getAttribute('data-url'), {method: 'POST', body: body(), credentials: 'same-origin'})
            .then(function(r) { return r.json(); })
            .then(function(j) {
                misses = 0;
                if (j.state === 'done') {
                    window.location.reload();
                    return;
                }
                if (j.state === 'error') {
                    box.classList.add('is-failed');
                    fail.hidden = false;
                    return;
                }
                if (j.message) {
                    text.textContent = j.message;
                }
                // busy: the model is reading somebody else's; wait longer before asking again
                window.setTimeout(next, j.state === 'busy' ? 5000 : 300);
            })
            .catch(function() {
                // a dropped connection is not a failure: the reading goes on at the server, so ask again
                misses++;
                if (misses > 8) {
                    box.classList.add('is-failed');
                    fail.hidden = false;
                    return;
                }
                window.setTimeout(next, 6000);
            });
    }
    next();
})();
{{/js}}
