# retoor <retoor@molodetz.nl>

import requests

from tests.api.quizzes._helpers import (
    JSON,
    build_published,
    create_quiz,
    signup,
)
from tests.conftest import BASE_URL


def test_the_hub_is_public(app_server, seeded_db):
    response = requests.get(f"{BASE_URL}/quizzes", headers=JSON)
    assert response.status_code == 200
    assert "quizzes" in response.json()


def test_the_hub_renders_html_for_a_browser(app_server, seeded_db):
    response = requests.get(f"{BASE_URL}/quizzes")
    assert response.status_code == 200
    assert "feed-layout" in response.text
    assert "sidebar-card" in response.text
    assert "feed-right" in response.text


def test_the_hub_exposes_the_scoreboard_and_counts(app_server, seeded_db):
    payload = requests.get(f"{BASE_URL}/quizzes", headers=JSON).json()
    assert "scoreboard" in payload
    assert "counts" in payload
    assert "pagination" in payload


def test_a_guest_cannot_create(app_server, seeded_db):
    payload = requests.get(f"{BASE_URL}/quizzes", headers=JSON).json()
    assert payload["viewer_can_create"] is False


def test_a_member_can_create(app_server, seeded_db):
    session, _ = signup()
    payload = session.get(f"{BASE_URL}/quizzes", headers=JSON).json()
    assert payload["viewer_can_create"] is True


def test_creating_a_quiz_returns_the_builder_url(app_server, seeded_db):
    session, _ = signup()
    response = session.post(
        f"{BASE_URL}/quizzes/create",
        data={"title": "My first quiz", "description": "d"},
        headers=JSON,
    )
    assert response.status_code == 200
    data = response.json()["data"]
    assert data["slug"]
    assert data["url"].endswith("/edit")


def test_creating_a_quiz_requires_auth(app_server, seeded_db):
    response = requests.post(
        f"{BASE_URL}/quizzes/create", data={"title": "Nope"}, headers=JSON
    )
    assert response.status_code in (401, 303)


def test_a_short_title_is_rejected(app_server, seeded_db):
    session, _ = signup()
    response = session.post(f"{BASE_URL}/quizzes/create", data={"title": "no"}, headers=JSON)
    assert response.status_code == 422


def test_a_new_quiz_starts_as_a_draft(app_server, seeded_db):
    session, _ = signup()
    slug = create_quiz(session)
    payload = session.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).json()
    assert payload["quiz"]["status"] == "draft"
    assert payload["quiz"]["viewer_can_edit"] is True


def test_a_draft_is_hidden_from_a_guest(app_server, seeded_db):
    session, _ = signup()
    slug = create_quiz(session)
    assert requests.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).status_code == 404


def test_a_draft_is_hidden_from_another_member(app_server, seeded_db):
    owner, _ = signup()
    slug = create_quiz(owner)
    other, _ = signup()
    assert other.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).status_code == 404


def test_the_owner_sees_their_draft(app_server, seeded_db):
    session, _ = signup()
    slug = create_quiz(session)
    assert session.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).status_code == 200


def test_an_admin_sees_another_members_draft(app_server, seeded_db):
    owner, _ = signup()
    slug = create_quiz(owner)
    admin = requests.Session()
    admin.post(
        f"{BASE_URL}/auth/login",
        data={"email": seeded_db["alice"]["email"], "password": seeded_db["alice"]["password"]},
        allow_redirects=True,
    )
    assert admin.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).status_code == 200


def test_a_published_quiz_is_public(app_server, seeded_db):
    session, _ = signup()
    slug = build_published(session, title="Public quiz")
    response = requests.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON)
    assert response.status_code == 200
    assert response.json()["quiz"]["status"] == "published"


def test_editing_a_draft_changes_its_settings(app_server, seeded_db):
    session, _ = signup()
    slug = create_quiz(session)
    session.post(
        f"{BASE_URL}/quizzes/edit/{slug}",
        data={"title": "Renamed quiz", "description": "changed", "pass_percent": "80"},
        headers=JSON,
    )
    payload = session.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).json()
    assert payload["quiz"]["title"] == "Renamed quiz"
    assert payload["quiz"]["pass_percent"] == 80


def test_another_member_cannot_edit(app_server, seeded_db):
    owner, _ = signup()
    slug = build_published(owner, title="Not yours")
    other, _ = signup()
    response = other.post(
        f"{BASE_URL}/quizzes/edit/{slug}", data={"title": "Hijacked"}, headers=JSON
    )
    assert response.status_code == 404


def test_the_owner_deletes_their_quiz(app_server, seeded_db):
    session, _ = signup()
    slug = build_published(session, title="Doomed quiz")
    assert session.post(f"{BASE_URL}/quizzes/delete/{slug}", headers=JSON).status_code == 200
    assert requests.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).status_code == 404


def test_an_admin_deletes_another_members_quiz(app_server, seeded_db):
    owner, _ = signup()
    slug = build_published(owner, title="Moderated quiz")
    admin = requests.Session()
    admin.post(
        f"{BASE_URL}/auth/login",
        data={"email": seeded_db["alice"]["email"], "password": seeded_db["alice"]["password"]},
        allow_redirects=True,
    )
    assert admin.post(f"{BASE_URL}/quizzes/delete/{slug}", headers=JSON).status_code == 200


def test_deleting_cascades_to_the_questions(app_server, seeded_db):
    from devplacepy.database import get_table, refresh_snapshot

    session, _ = signup()
    slug = build_published(session, title="Cascade quiz")
    refresh_snapshot()
    quiz = get_table("quizzes").find_one(slug=slug)
    session.post(f"{BASE_URL}/quizzes/delete/{slug}", headers=JSON)
    refresh_snapshot()
    for table in ("quiz_questions", "quiz_options"):
        assert get_table(table).count(quiz_uid=quiz["uid"], deleted_at=None) == 0


def test_the_delete_cascade_shares_one_stamp(app_server, seeded_db):
    from devplacepy.database import get_table, refresh_snapshot

    session, _ = signup()
    slug = build_published(session, title="Stamped quiz")
    attempt_owner, _ = signup()
    attempt_owner.post(f"{BASE_URL}/quizzes/{slug}/attempts", headers=JSON)
    refresh_snapshot()
    quiz = get_table("quizzes").find_one(slug=slug)
    session.post(f"{BASE_URL}/quizzes/delete/{slug}", headers=JSON)
    refresh_snapshot()
    stamps = set()
    for table in ("quiz_questions", "quiz_options", "quiz_attempts", "quiz_answers"):
        for row in get_table(table).find(quiz_uid=quiz["uid"]):
            stamps.add(row["deleted_at"])
    assert len(stamps) == 1
    assert next(iter(stamps))


def test_the_todo_filter_excludes_a_completed_quiz(app_server, seeded_db):
    from tests.api.quizzes._helpers import (
        answer_correctly,
        attempt_state,
        start_attempt,
    )

    owner, _ = signup()
    slug = build_published(owner, title="Todo filter quiz")
    player, _ = signup()
    before = player.get(f"{BASE_URL}/quizzes?filter=todo", headers=JSON).json()
    assert any(item["slug"] == slug for item in before["quizzes"])
    attempt_uid = start_attempt(player, slug)
    state = attempt_state(player, slug, attempt_uid)
    for question in state["attempt"]["questions"]:
        answer_correctly(player, slug, attempt_uid, question)
    player.post(f"{BASE_URL}/quizzes/{slug}/attempts/{attempt_uid}/finish", headers=JSON)
    after = player.get(f"{BASE_URL}/quizzes?filter=todo", headers=JSON).json()
    assert not any(item["slug"] == slug for item in after["quizzes"])
    done = player.get(f"{BASE_URL}/quizzes?filter=done", headers=JSON).json()
    assert any(item["slug"] == slug for item in done["quizzes"])


def test_the_mine_filter_lists_only_the_viewers_quizzes(app_server, seeded_db):
    session, _ = signup()
    slug = build_published(session, title="Mine filter quiz")
    payload = session.get(f"{BASE_URL}/quizzes?filter=mine", headers=JSON).json()
    assert all(item["author"]["username"] for item in payload["quizzes"])
    assert any(item["slug"] == slug for item in payload["quizzes"])


def test_the_drafts_filter_lists_only_drafts(app_server, seeded_db):
    session, _ = signup()
    draft_slug = create_quiz(session, "Draft filter quiz")
    published_slug = build_published(session, title="Published filter quiz")
    payload = session.get(f"{BASE_URL}/quizzes?filter=drafts", headers=JSON).json()
    slugs = [item["slug"] for item in payload["quizzes"]]
    assert draft_slug in slugs
    assert published_slug not in slugs


def test_a_guest_gets_no_personal_filters(app_server, seeded_db):
    payload = requests.get(f"{BASE_URL}/quizzes?filter=todo", headers=JSON).json()
    assert payload["quizzes"] == []


def test_search_matches_the_title(app_server, seeded_db):
    session, _ = signup()
    slug = build_published(session, title="Highly searchable haddock quiz")
    payload = requests.get(f"{BASE_URL}/quizzes?search=haddock", headers=JSON).json()
    assert any(item["slug"] == slug for item in payload["quizzes"])


def test_search_matches_the_author_username(app_server, seeded_db):
    session, name = signup("searchable")
    build_published(session, title="Author search quiz")
    payload = requests.get(f"{BASE_URL}/quizzes?search={name}", headers=JSON).json()
    assert any(item["author"]["username"] == name for item in payload["quizzes"])


def test_an_unknown_filter_falls_back_to_all(app_server, seeded_db):
    payload = requests.get(f"{BASE_URL}/quizzes?filter=nonsense", headers=JSON).json()
    assert payload["filter"] == "all"


def test_the_listing_carries_the_viewer_state(app_server, seeded_db):
    session, _ = signup()
    slug = build_published(session, title="Viewer state quiz")
    other, _ = signup()
    payload = other.get(f"{BASE_URL}/quizzes", headers=JSON).json()
    row = next(item for item in payload["quizzes"] if item["slug"] == slug)
    assert row["viewer_state"] == "todo"
    assert row["question_count"] == 2
    assert row["total_points"] == 3


def test_a_quiz_accepts_a_comment_and_counts_it(app_server, seeded_db):
    from devplacepy.database import get_table, refresh_snapshot

    session, _ = signup()
    slug = build_published(session, title="Commented quiz")
    refresh_snapshot()
    quiz = get_table("quizzes").find_one(slug=slug)
    session.post(
        f"{BASE_URL}/comments/create",
        data={"content": "Nice quiz", "target_uid": quiz["uid"], "target_type": "quiz"},
        headers=JSON,
    )
    payload = requests.get(f"{BASE_URL}/quizzes", headers=JSON).json()
    row = next(item for item in payload["quizzes"] if item["slug"] == slug)
    assert row["comment_count"] == 1


def test_a_quiz_accepts_a_star_vote(app_server, seeded_db):
    from devplacepy.database import get_table, refresh_snapshot

    session, _ = signup()
    slug = build_published(session, title="Voted quiz")
    refresh_snapshot()
    quiz = get_table("quizzes").find_one(slug=slug)
    voter, _ = signup()
    voter.post(f"{BASE_URL}/votes/quiz/{quiz['uid']}", data={"value": "1"}, headers=JSON)
    payload = requests.get(f"{BASE_URL}/quizzes/{slug}", headers=JSON).json()
    assert payload["star_count"] == 1


def test_the_bare_uid_resolves_like_the_slug(app_server, seeded_db):
    from devplacepy.database import get_table, refresh_snapshot

    session, _ = signup()
    slug = build_published(session, title="Uid lookup quiz")
    refresh_snapshot()
    quiz = get_table("quizzes").find_one(slug=slug)
    response = requests.get(f"{BASE_URL}/quizzes/{quiz['uid']}", headers=JSON)
    assert response.status_code == 200


def test_an_unknown_quiz_is_a_404(app_server, seeded_db):
    assert requests.get(f"{BASE_URL}/quizzes/nope-nope", headers=JSON).status_code == 404


def test_the_new_quiz_page_requires_auth(app_server, seeded_db):
    response = requests.get(f"{BASE_URL}/quizzes/new", headers=JSON, allow_redirects=False)
    assert response.status_code in (401, 303)


def test_the_new_quiz_page_renders_for_a_member(app_server, seeded_db):
    session, _ = signup()
    response = session.get(f"{BASE_URL}/quizzes/new")
    assert response.status_code == 200
    assert "quiz-form" in response.text


def test_the_hub_nav_entry_is_visible_to_a_guest(app_server, seeded_db):
    response = requests.get(f"{BASE_URL}/quizzes")
    assert 'href="/quizzes"' in response.text
    assert "Quizzes" in response.text
