# retoor <retoor@molodetz.nl>

import requests

from tests.conftest import BASE_URL

JSON = {"Accept": "application/json"}

CHOICE = {
    "kind": "single_choice",
    "prompt": "Which journal mode allows concurrent readers?",
    "points": 2,
    "options": "DELETE\nWAL",
    "correct_indexes": "1",
}

NUMERIC = {
    "kind": "numeric",
    "prompt": "How many bytes are in a kibibyte?",
    "points": 1,
    "numeric_value": "1024",
    "numeric_tolerance": "0",
}

DIALOG_CONFIRM = ".dialog-confirm"

_counter = [0]


def _author_quiz(title, questions=(CHOICE, NUMERIC), **settings):
    _counter[0] += 1
    name = f"play{abs(hash(title)) % 10**8}{_counter[0]}"
    session = requests.Session()
    session.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": f"{name}@t.dev",
            "password": "secret123",
            "confirm_password": "secret123",
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    payload = {"title": title, "description": "d", **settings}
    slug = session.post(f"{BASE_URL}/quizzes/create", data=payload, headers=JSON).json()["data"][
        "slug"
    ]
    for question in questions:
        session.post(f"{BASE_URL}/quizzes/{slug}/questions", data=question, headers=JSON)
    session.post(f"{BASE_URL}/quizzes/{slug}/publish", headers=JSON)
    return slug


def _start(page, slug):
    page.goto(f"{BASE_URL}/quizzes/{slug}", wait_until="domcontentloaded")
    page.locator(".quiz-detail-actions button:has-text('Start quiz')").click()
    page.wait_for_url("**/attempts/**", wait_until="domcontentloaded")
    page.locator("dp-quiz-player").wait_for(state="visible")


def test_starting_opens_the_player(alice):
    page, _ = alice
    slug = _author_quiz("Player opens quiz")
    _start(page, slug)
    assert page.locator(".quiz-question").count() == 2
    page.locator(".quiz-hud").wait_for(state="visible")


def test_the_player_shows_one_question_at_a_time(alice):
    page, _ = alice
    slug = _author_quiz("Player one at a time quiz")
    _start(page, slug)
    questions = page.locator(".quiz-question")
    assert questions.nth(0).is_visible()
    assert not questions.nth(1).is_visible()
    page.locator(".quiz-slide-nav button:has-text('Next')").click()
    assert not questions.nth(0).is_visible()
    assert questions.nth(1).is_visible()
    page.locator(".quiz-slide-nav button:has-text('Previous')").click()
    assert questions.nth(0).is_visible()
    assert not questions.nth(1).is_visible()


def test_answering_advances_to_the_next_question(alice):
    page, _ = alice
    slug = _author_quiz("Player advance quiz")
    _start(page, slug)
    questions = page.locator(".quiz-question")
    questions.nth(0).locator("input[type='radio']").last.check()
    questions.nth(0).locator("button:has-text('Submit answer')").click()
    questions.nth(0).locator(".quiz-grade").wait_for(state="visible")
    questions.nth(1).wait_for(state="visible")
    assert not questions.nth(0).is_visible()


def test_the_player_renders_a_real_form_per_question(alice):
    page, _ = alice
    slug = _author_quiz("Player forms quiz")
    _start(page, slug)
    forms = page.locator("form[data-quiz-answer-form]")
    assert forms.count() == 2
    assert forms.first.get_attribute("method").lower() == "post"


def test_answering_a_choice_shows_the_grade_in_place(alice):
    page, _ = alice
    slug = _author_quiz("Player grade quiz")
    _start(page, slug)
    question = page.locator(".quiz-question-single_choice").first
    question.locator("input[type='radio']").last.check()
    question.locator("button:has-text('Submit answer')").click()
    question.locator(".quiz-grade-correct").wait_for(state="visible")
    assert "Correct" in question.locator(".quiz-grade-verdict").inner_text()


def test_a_wrong_answer_is_reported(alice):
    page, _ = alice
    slug = _author_quiz("Player wrong quiz")
    _start(page, slug)
    question = page.locator(".quiz-question-single_choice").first
    question.locator("input[type='radio']").first.check()
    question.locator("button:has-text('Submit answer')").click()
    question.locator(".quiz-grade-wrong").wait_for(state="visible")


def test_the_hud_updates_after_an_answer(alice):
    page, _ = alice
    slug = _author_quiz("Player hud quiz")
    _start(page, slug)
    before = page.locator("[data-quiz-progress]").inner_text()
    question = page.locator(".quiz-question-single_choice").first
    question.locator("input[type='radio']").last.check()
    question.locator("button:has-text('Submit answer')").click()
    question.locator(".quiz-grade").wait_for(state="visible")
    page.wait_for_function(
        "before => document.querySelector('[data-quiz-progress]').textContent !== before",
        arg=before,
    )
    assert "1 / 2 answered" in page.locator("[data-quiz-progress]").inner_text()
    assert "2 / 3 points" in page.locator("[data-quiz-score]").inner_text()


def test_an_answered_question_cannot_be_resubmitted(alice):
    page, _ = alice
    slug = _author_quiz("Player once quiz")
    _start(page, slug)
    question = page.locator(".quiz-question-single_choice").first
    question.locator("input[type='radio']").last.check()
    question.locator("button:has-text('Submit answer')").click()
    question.locator(".quiz-grade").wait_for(state="visible")
    assert question.locator("button:has-text('Submit answer')").count() == 0
    assert question.locator("input[type='radio']").first.is_disabled()


def test_a_numeric_question_takes_a_typed_answer(alice):
    page, _ = alice
    slug = _author_quiz("Player numeric quiz", questions=(NUMERIC,))
    _start(page, slug)
    question = page.locator(".quiz-question-numeric").first
    question.locator("input[name='answer_text']").fill("1024")
    question.locator("button:has-text('Submit answer')").click()
    question.locator(".quiz-grade-correct").wait_for(state="visible")


def test_the_timer_is_rendered_for_a_limited_quiz(alice):
    page, _ = alice
    slug = _author_quiz("Player timer quiz", time_limit_seconds="600")
    _start(page, slug)
    timer = page.locator("[data-quiz-timer]")
    timer.wait_for(state="visible")
    assert timer.inner_text().strip()


def test_no_timer_is_rendered_without_a_limit(alice):
    page, _ = alice
    slug = _author_quiz("Player untimed quiz")
    _start(page, slug)
    page.locator(".quiz-hud").wait_for(state="visible")
    assert page.locator("[data-quiz-timer]").count() == 0


def test_the_answer_key_is_not_in_the_page_source(alice):
    page, _ = alice
    slug = _author_quiz("Player hidden key quiz", questions=(NUMERIC,), reveal_answers="0")
    _start(page, slug)
    assert "1024" not in page.content()


def test_reloading_resumes_the_same_attempt(alice):
    page, _ = alice
    slug = _author_quiz("Player resume quiz")
    _start(page, slug)
    attempt_url = page.url
    question = page.locator(".quiz-question-single_choice").first
    question.locator("input[type='radio']").last.check()
    question.locator("button:has-text('Submit answer')").click()
    question.locator(".quiz-grade").wait_for(state="visible")
    page.goto(f"{BASE_URL}/quizzes/{slug}", wait_until="domcontentloaded")
    page.locator(".quiz-detail-actions a:has-text('Resume attempt')").click()
    page.wait_for_url("**/attempts/**", wait_until="domcontentloaded")
    assert page.url == attempt_url
    assert page.locator(".quiz-question-answered").count() == 1


def test_finishing_reaches_the_results_page(alice):
    page, _ = alice
    slug = _author_quiz("Player finish quiz", pass_percent="50")
    _start(page, slug)
    for question in (".quiz-question-single_choice", ".quiz-question-numeric"):
        node = page.locator(question).first
        if "numeric" in question:
            node.locator("input[name='answer_text']").fill("1024")
        else:
            node.locator("input[type='radio']").last.check()
        node.locator("button:has-text('Submit answer')").click()
        node.locator(".quiz-grade").wait_for(state="visible")
    page.locator("form[data-quiz-finish-form] button").click()
    page.locator(DIALOG_CONFIRM).wait_for(state="visible")
    page.locator(DIALOG_CONFIRM).click()
    page.wait_for_url("**/results", wait_until="domcontentloaded")
    page.locator(".quiz-score-card").wait_for(state="visible")
    assert "100" in page.locator(".quiz-score-percent").inner_text()


def test_the_results_page_shows_the_pass_verdict(alice):
    page, _ = alice
    slug = _author_quiz("Player verdict quiz", questions=(NUMERIC,), pass_percent="50")
    _start(page, slug)
    node = page.locator(".quiz-question-numeric").first
    node.locator("input[name='answer_text']").fill("1024")
    node.locator("button:has-text('Submit answer')").click()
    node.locator(".quiz-grade").wait_for(state="visible")
    page.locator("form[data-quiz-finish-form] button").click()
    page.locator(DIALOG_CONFIRM).wait_for(state="visible")
    page.locator(DIALOG_CONFIRM).click()
    page.wait_for_url("**/results", wait_until="domcontentloaded")
    page.locator(".quiz-verdict-pass").wait_for(state="visible")


def test_the_results_page_reviews_every_answer(alice):
    page, _ = alice
    slug = _author_quiz("Player review quiz", allow_review="1")
    _start(page, slug)
    node = page.locator(".quiz-question-single_choice").first
    node.locator("input[type='radio']").last.check()
    node.locator("button:has-text('Submit answer')").click()
    node.locator(".quiz-grade").wait_for(state="visible")
    page.locator("form[data-quiz-finish-form] button").click()
    page.locator(DIALOG_CONFIRM).wait_for(state="visible")
    page.locator(DIALOG_CONFIRM).click()
    page.wait_for_url("**/results", wait_until="domcontentloaded")
    page.locator(".quiz-review").wait_for(state="visible")
    assert page.locator(".quiz-review-item").count() == 2


def test_the_review_is_hidden_when_the_author_disabled_it(alice):
    page, _ = alice
    slug = _author_quiz("Player no review quiz", questions=(NUMERIC,), allow_review="0")
    _start(page, slug)
    node = page.locator(".quiz-question-numeric").first
    node.locator("input[name='answer_text']").fill("1024")
    node.locator("button:has-text('Submit answer')").click()
    node.locator(".quiz-grade").wait_for(state="visible")
    page.locator("form[data-quiz-finish-form] button").click()
    page.locator(DIALOG_CONFIRM).wait_for(state="visible")
    page.locator(DIALOG_CONFIRM).click()
    page.wait_for_url("**/results", wait_until="domcontentloaded")
    page.locator(".quiz-review-disabled").wait_for(state="visible")


def test_the_results_page_offers_a_replay(alice):
    page, _ = alice
    slug = _author_quiz("Player replay quiz", questions=(NUMERIC,))
    _start(page, slug)
    node = page.locator(".quiz-question-numeric").first
    node.locator("input[name='answer_text']").fill("1024")
    node.locator("button:has-text('Submit answer')").click()
    node.locator(".quiz-grade").wait_for(state="visible")
    page.locator("form[data-quiz-finish-form] button").click()
    page.locator(DIALOG_CONFIRM).wait_for(state="visible")
    page.locator(DIALOG_CONFIRM).click()
    page.wait_for_url("**/results", wait_until="domcontentloaded")
    page.locator(".quiz-results-actions button:has-text('Play again')").click()
    page.wait_for_url("**/attempts/**", wait_until="domcontentloaded")
    page.locator("dp-quiz-player").wait_for(state="visible")


def test_the_hub_shows_the_completed_badge_afterwards(alice):
    page, _ = alice
    slug = _author_quiz("Player badge quiz", questions=(NUMERIC,))
    _start(page, slug)
    node = page.locator(".quiz-question-numeric").first
    node.locator("input[name='answer_text']").fill("1024")
    node.locator("button:has-text('Submit answer')").click()
    node.locator(".quiz-grade").wait_for(state="visible")
    page.locator("form[data-quiz-finish-form] button").click()
    page.locator(DIALOG_CONFIRM).wait_for(state="visible")
    page.locator(DIALOG_CONFIRM).click()
    page.wait_for_url("**/results", wait_until="domcontentloaded")
    page.goto(f"{BASE_URL}/quizzes?filter=done", wait_until="domcontentloaded")
    card = page.locator(f".quiz-card:has(a[href='/quizzes/{slug}'])").first
    card.wait_for(state="visible")
    assert card.locator(".quiz-state-done").count() == 1
