import pytest
from django.urls import reverse
from django.contrib.auth.models import Group, User
from django.test import Client

SAFE_STATUS_CODES = {200, 301, 302, 303, 403, 404, 405}

@pytest.fixture
def candidate_client(db):
    user = User.objects.create_user(username="candidate", password="password", email="candidate@test.com")
    client = Client()
    client.force_login(user)
    return client

@pytest.fixture
def superuser_client(db):
    user = User.objects.create_superuser(username="superuser", password="password", email="superuser@test.com")
    for group_name in ["sba_checker", "cid_user_manager"]:
        g, _ = Group.objects.get_or_create(name=group_name)
        user.groups.add(g)
    client = Client()
    client.force_login(user)
    return client

@pytest.fixture
def anonymous_client(db):
    return Client()

@pytest.fixture
def smoke_data(db, settings, tmp_path):
    from sbas.models import Question, Exam, UserAnswer, Category
    settings.MEDIA_ROOT = str(tmp_path)

    create_user = User.objects.create_user(username="smoke_user", email="smoke_user@test.com")

    cat, _ = Category.objects.get_or_create(category="Test Category")

    question = Question.objects.create(
        stem="Test Stem",
        a_answer="Ans A",
        b_answer="Ans B",
        c_answer="Ans C",
        d_answer="Ans D",
        e_answer="Ans E",
        best_answer="a",
        category=cat,
    )

    exam = Exam.objects.create(
        name="Test SBA Exam",
        exam_mode=True,
        active=True
    )
    exam.author.add(create_user)

    from sbas.models import ExamQuestionDetail
    ExamQuestionDetail.objects.create(exam=exam, question=question, sort_order=1)

    user_answer = UserAnswer.objects.create(
        user=create_user,
        exam=exam,
        question=question,
        answer="a",
    )

    return {
        "question": question,
        "exam": exam,
        "user_answer": user_answer,
    }

URL_SPECS = [
    ("sbas:question_view", None),
    ("sbas:question_create", None),
    ("sbas:question_update", lambda d: {"pk": d["question"].pk}),
    ("sbas:question_clone", lambda d: {"pk": d["question"].pk}),
    ("sbas:question_delete", lambda d: {"pk": d["question"].pk}),
    ("sbas:exam_markers", lambda d: {"pk": d["exam"].pk}),
    ("sbas:exam_groups_edit", lambda d: {"pk": d["exam"].pk}),
    ("sbas:exam_authors", lambda d: {"pk": d["exam"].pk}),
    ("sbas:exam_clone", lambda d: {"exam_id": d["exam"].pk}),
    ("sbas:exam_clone2", lambda d: {"exam_id": d["exam"].pk}),
    ("sbas:active_exams", None),
    ("sbas:exam_create", None),
    ("sbas:exam_update", lambda d: {"pk": d["exam"].pk}),
    ("sbas:exam_delete", lambda d: {"pk": d["exam"].pk}),
    ("sbas:user_answer_table_view", None),
    ("sbas:user_answer_view", lambda d: {"pk": d["user_answer"].pk}),
    ("sbas:user_answer_delete", lambda d: {"pk": d["user_answer"].pk}),
    ("sbas:llm_prompt_view", None),
    ("sbas:import_llm_questions", None),
    ("sbas:import_llm_confirm", None),
    ("sbas:exam_create_from_filters_with_name", None),
    ("sbas:generate_exam", None),
    ("sbas:question_overview", None),
    ("sbas:question_search_page", None),
    ("sbas:question_search_partial", None),
    ("sbas:exam_review_question_responses", lambda d: {"pk": d["exam"].pk, "q_index": 0}),
    ("sbas:exam_review_question_summary", lambda d: {"pk": d["exam"].pk, "q_index": 0}),
    ("sbas:toggle_frcr", lambda d: {"pk": d["question"].pk}),
    ("sbas:merge_category", None),
    ("sbas:index", None),
    ("sbas:help", None),
]

@pytest.mark.django_db
@pytest.mark.parametrize("url_name, kwargs_lambda", URL_SPECS)
def test_url_smoke_anonymous(anonymous_client, smoke_data, url_name, kwargs_lambda):
    kwargs = kwargs_lambda(smoke_data) if kwargs_lambda else None
    url = reverse(url_name, kwargs=kwargs)
    response = anonymous_client.get(url, follow=False)
    assert response.status_code != 500, f"500 Server Error on {url_name} ({url}) for Anonymous"
    assert response.status_code in {200, 302, 400, 403, 404, 405}, f"Unexpected status code {response.status_code} on {url_name} for Anonymous"

@pytest.mark.django_db
@pytest.mark.parametrize("url_name, kwargs_lambda", URL_SPECS)
def test_url_smoke_candidate(candidate_client, smoke_data, url_name, kwargs_lambda):
    kwargs = kwargs_lambda(smoke_data) if kwargs_lambda else None
    url = reverse(url_name, kwargs=kwargs)
    response = candidate_client.get(url, follow=False)
    assert response.status_code != 500, f"500 Server Error on {url_name} ({url}) for Candidate"
    assert response.status_code in SAFE_STATUS_CODES or response.status_code == 400, f"Unexpected status code {response.status_code} on {url_name} for Candidate"

@pytest.mark.django_db
@pytest.mark.parametrize("url_name, kwargs_lambda", URL_SPECS)
def test_url_smoke_superuser(superuser_client, smoke_data, url_name, kwargs_lambda):
    kwargs = kwargs_lambda(smoke_data) if kwargs_lambda else None
    url = reverse(url_name, kwargs=kwargs)
    response = superuser_client.get(url, follow=False)
    assert response.status_code != 500, f"500 Server Error on {url_name} ({url}) for Superuser"
    assert response.status_code in {200, 301, 302, 303, 400, 403, 404, 405}, f"Unexpected status code {response.status_code} on {url_name} for Superuser"
