from http import HTTPStatus
import json
import os
from re import A
from django.conf import settings
import pytest

import tempfile

# from django.contrib.auth.models import User
from django.urls import reverse

from rich.pretty import pprint

from bs4 import BeautifulSoup

from sbas.views import GenericExamViews as SbaExamViews

from sbas.models import Category, UserAnswer, Exam, Question

from generic.models import CidUser, CidUserGroup, UserUserGroup
from rad.tests.test_helpers import AssertNotFound, ExamTester, create_cid_user_and_groups, create_exam

from django.contrib.auth.models import User


APP_NAME = "sbas"



def create_category(db):
    category = Category.objects.create(category="test category")
    category.save()
    category = Category.objects.create(category="test category 2")
    category.save()


def create_question(exam, answer=None):
    # Just assign random stuff

    if answer is None:
        best_answer = "a"
    else:
        best_answer = answer
    question: Question = Question.objects.create(
        stem="test question stem",
        a_answer="question a text",
        a_feedback="question a feedback",
        b_answer="question b text",
        b_feedback="question b feedback",
        c_answer="question c text",
        c_feedback="question c feedback",
        d_answer="question d text",
        d_feedback="question d feedback",
        e_answer="question e text",
        e_feedback="question e feedback",
        best_answer=best_answer,
    )
    question.exams.set([exam])

    return question


def test_exams(db, client):
    create_category(db)

    exam_tester = ExamTester(db, client, APP_NAME, SbaExamViews)

    exam_tester.create_questions(create_question)

    users_tested = 1

    # for cid_user in [cid_user_1001, cid_user_1000, user1, user2]:
    for cid_user in exam_tester.all_users:

        exam_tester.load_user(cid_user)
        exam = exam_tester.exam
        exam.active = False
        exam.save()

        exam_tester.check_active_exams(0)


        exam.active = True
        exam.publish_results = False
        exam.save()

        exam_tester.check_onsite_start_page()

        #check_onsite_start_page

        exam_tester.check_take_page()

        exam_tester.check_take_overview(answered=0, total=3)


        # Loop through questions again to test submissions
        # All physics questions have 5 parts (and require a csrf token)
        questions_len = len(exam_tester.generated_questions) - 1
        for n, question in enumerate(exam_tester.generated_questions):
            if exam_tester.testing_cid_user:
                question_url = reverse(
                    f"{APP_NAME}:exam_take",
                    kwargs={
                        "pk": exam.pk,
                        "sk": n,
                        "cid": exam_tester.current_user.cid,
                        "passcode": exam_tester.current_user.passcode,
                    },
                )
            else:
                question_url = reverse(
                    f"{APP_NAME}:exam_take_user",
                    kwargs={
                        "pk": exam.pk,
                        "sk": n,
                    },
                )

            # Request the full page which now loads the fragment via HTMX;
            # fetch the fragment endpoint directly to get the form and CSRF token.
            cid_take_res = client.get(question_url)

            if cid_user in exam_tester.invalid_users:
                assert cid_take_res.status_code == HTTPStatus.NOT_FOUND
                continue
            else:
                assert cid_take_res.status_code == HTTPStatus.OK

            # The full page should include the HTMX container which will load
            # the fragment client-side. Assert the container exists and has an
            # hx-get attribute pointing to a fragment endpoint.
            main_soup = BeautifulSoup(cid_take_res.content, "html.parser")
            container = main_soup.find("div", attrs={"id": "question-fragment"})
            assert container is not None, "Missing #question-fragment container"
            hxget = container.get("hx-get") or container.get("data-hx-get")
            assert hxget and "take_fragment" in hxget, f"Container hx-get not pointing to fragment: {hxget}"

            # Build fragment URL and fetch it to obtain CSRF token and controls
            if exam_tester.testing_cid_user:
                frag_url = reverse(
                    f"{APP_NAME}:exam_take_fragment",
                    kwargs={
                        "pk": exam.pk,
                        "sk": n,
                        "cid": exam_tester.current_user.cid,
                        "passcode": exam_tester.current_user.passcode,
                    },
                )
            else:
                frag_url = reverse(
                    f"{APP_NAME}:exam_take_fragment_user",
                    kwargs={
                        "pk": exam.pk,
                        "sk": n,
                    },
                )

            frag_res = client.get(frag_url)
            assert frag_res.status_code == HTTPStatus.OK
            cid_take_soup = BeautifulSoup(frag_res.content, "html.parser")

            # Extract csrftoken from fragment
            csrftoken = cid_take_soup.find("input", attrs={"name": "csrfmiddlewaretoken"})["value"]

            # Ensure fragment contains the question stem and answer list
            assert "test question stem" in frag_res.text
            # check answer choices exist with data-ans attributes
            assert cid_take_soup.find("li", attrs={"data-ans": "a"}), "Missing answer choice a in fragment"
            assert "question a text" in frag_res.text
            # Send answers (all TRUE)
            post_json = {
                "csrfmiddlewaretoken": csrftoken,
                "answer": "a",
                "next": "",
            }
            res = client.post(question_url, data=post_json)

            next_button = cid_take_soup.find("button", attrs={"name": "next"})

            # Our final question will trigger a bad request (it shouldn't show a next button)
            # We currently do still save the form though....
            if questions_len == n:
                assert next_button == None
                assert res.status_code == HTTPStatus.BAD_REQUEST
            else:
                assert next_button
                assert res.status_code == HTTPStatus.FOUND

            overview_button = cid_take_soup.find("button", attrs={"name": "finish"})
            assert overview_button

            previous_button = cid_take_soup.find("button", attrs={"name": "previous"})

            if n > 0:
                assert previous_button
            else:
                assert not previous_button

            # Filter answer to the question we just submitted to
            cid_user_answers = question.cid_user_answers.all()

            assert len(cid_user_answers) == users_tested

            if exam_tester.testing_cid_user:
                cid_user_answer = cid_user_answers.filter(cid=exam_tester.current_user.cid)[0]
            else:
                cid_user_answer = cid_user_answers.filter(user=exam_tester.current_user)[0]

            assert all(cid_user_answer.get_answer())

        # Recheck the overview page (now that we have submitted answers)
        exam_tester.check_take_overview(3, 3)


        exam_tester.check_cid_scores_page()


        exam_tester.check_cid_scores_user_page()

        # The rest of the tests are for valid users
        if exam_tester.current_user in exam_tester.invalid_users:
            continue

        # answer the final question
        extra_question = exam_tester.generated_questions[-1]
        if exam_tester.testing_cid_user:
            cid_user_answer = UserAnswer(
                question=extra_question,
                answer = "a",
                cid=cid_user.cid,
                exam=exam,
            )
        else:
            cid_user_answer = UserAnswer(
                question=extra_question,
                answer = "a",
                user=exam_tester.current_user,
                exam=exam,
            )
        cid_user_answer.save()

        exam_tester.check_cid_scores_user_page2()


        users_tested = users_tested + 1
