import pytest
from django.urls import reverse
from django.contrib.contenttypes.models import ContentType
from survey.models import Survey, SurveyQuestion, SurveyResponse, SurveyAnswer
from survey.views import check_survey_interception
from atlas.models import CaseCollection

@pytest.mark.django_db
def test_survey_creation():
    survey = Survey.objects.create(name="Test Course Survey", description="Feedback on course")
    assert survey.name == "Test Course Survey"
    assert survey.active is True
    assert survey.anonymous is False

@pytest.mark.django_db
def test_survey_questions():
    survey = Survey.objects.create(name="Test Survey")
    q1 = SurveyQuestion.objects.create(
        survey=survey,
        text="Rate this case",
        question_type=SurveyQuestion.QuestionType.RATING,
        position=10
    )
    q2 = SurveyQuestion.objects.create(
        survey=survey,
        text="Any comments?",
        question_type=SurveyQuestion.QuestionType.TEXT,
        position=20
    )
    assert survey.questions.count() == 2
    assert q1.get_choices_list() == []

@pytest.mark.django_db
def test_survey_response_and_answers(admin_user):
    survey = Survey.objects.create(name="Test Survey")
    q1 = SurveyQuestion.objects.create(
        survey=survey, text="Rate this case", question_type=SurveyQuestion.QuestionType.RATING
    )
    
    # Simulate a survey response save
    response = SurveyResponse.objects.create(
        survey=survey,
        user=admin_user,
        pre_or_post="PRE"
    )
    answer = SurveyAnswer.objects.create(
        response=response,
        question=q1,
        rating_answer=4
    )
    
    assert response.answers.count() == 1
    assert answer.rating_answer == 4

@pytest.mark.django_db
def test_interception_helper(rf, admin_user):
    survey = Survey.objects.create(name="Pre-take survey")
    collection = CaseCollection.objects.create(name="Test Collection", pre_survey=survey)
    
    request = rf.get('/atlas/collection/1/take/')
    request.user = admin_user
    
    # 1. First check: should redirect to pre-survey since they haven't filled it out
    redirect_response = check_survey_interception(request, collection)
    assert redirect_response is not None
    assert "take/" in redirect_response.url
    
    # 2. Add response and check again: should not redirect
    ct = ContentType.objects.get_for_model(collection)
    resp = SurveyResponse.objects.create(
        survey=survey,
        user=admin_user,
        content_type=ct,
        object_id=collection.pk,
        pre_or_post="PRE"
    )
    
    no_redirect_response = check_survey_interception(request, collection)
    assert no_redirect_response is None

@pytest.mark.django_db
def test_survey_authorship(admin_user):
    survey = Survey.objects.create(name="Author Test Survey")
    survey.add_author(admin_user)
    assert survey.is_author(admin_user) is True
    assert admin_user in survey.get_author_objects()
    assert survey.get_authors() == admin_user.username

@pytest.mark.django_db
def test_can_manage_survey_permission(admin_user, django_user_model):
    from survey.views import can_manage_survey
    from django.contrib.auth.models import Group
    
    survey = Survey.objects.create(name="Permissions Test Survey", authors_only=True)
    
    # 1. Non-staff user should not have permission
    regular_user = django_user_model.objects.create_user(username="trainee", password="pw")
    assert can_manage_survey(regular_user, survey) is False
    
    # 2. Staff user in cid_user_manager but not author should not have permission for private survey
    manager_group, _ = Group.objects.get_or_create(name="cid_user_manager")
    manager_user = django_user_model.objects.create_user(username="manager", password="pw")
    manager_user.groups.add(manager_group)
    assert can_manage_survey(manager_user, survey) is False
    
    # 3. Superuser should always have permission
    superuser = django_user_model.objects.create_superuser(username="admin2", password="pw")
    assert can_manage_survey(superuser, survey) is True
    
    # 4. Author should have permission even if private
    survey.add_author(manager_user)
    assert can_manage_survey(manager_user, survey) is True
    
    # 5. Non-author manager should have permission if survey is public
    survey.authors_only = False
    survey.save()
    other_manager = django_user_model.objects.create_user(username="other_manager", password="pw")
    other_manager.groups.add(manager_group)
    assert can_manage_survey(other_manager, survey) is True

@pytest.mark.django_db
def test_integer_and_date_validation():
    from survey.forms import SurveyTakeForm
    survey = Survey.objects.create(name="Validation Test Survey")
    
    # 1. Integer question with min=10, max=50
    q_int = SurveyQuestion.objects.create(
        survey=survey,
        text="Enter age",
        question_type=SurveyQuestion.QuestionType.INTEGER,
        validation_rules={"min_value": 10, "max_value": 50}
    )
    
    # 2. Date question with min="2026-01-01", max="2026-12-31"
    q_date = SurveyQuestion.objects.create(
        survey=survey,
        text="Select target date",
        question_type=SurveyQuestion.QuestionType.DATE,
        validation_rules={"min_date": "2026-01-01", "max_date": "2026-12-31"}
    )
    
    # Valid submission
    form_valid = SurveyTakeForm(
        data={
            f"question_{q_int.pk}": 25,
            f"question_{q_date.pk}": "2026-06-15"
        },
        survey=survey
    )
    assert form_valid.is_valid() is True
    
    # Out of bounds Integer submission
    form_invalid_int = SurveyTakeForm(
        data={
            f"question_{q_int.pk}": 5,
            f"question_{q_date.pk}": "2026-06-15"
        },
        survey=survey
    )
    assert form_invalid_int.is_valid() is False
    assert f"question_{q_int.pk}" in form_invalid_int.errors
    
    # Out of bounds Date submission
    form_invalid_date = SurveyTakeForm(
        data={
            f"question_{q_int.pk}": 25,
            f"question_{q_date.pk}": "2027-01-01"
        },
        survey=survey
    )
    assert form_invalid_date.is_valid() is False
    assert f"question_{q_date.pk}" in form_invalid_date.errors


@pytest.mark.django_db
def test_survey_skip(rf, admin_user):
    survey = Survey.objects.create(name="Optional pre-take survey")
    collection = CaseCollection.objects.create(name="Test Collection", pre_survey=survey, pre_survey_mandatory=False)
    
    request = rf.get('/atlas/collection/1/take/')
    request.user = admin_user
    
    # Initialize session middleware mock
    from django.contrib.sessions.middleware import SessionMiddleware
    middleware = SessionMiddleware(lambda req: None)
    middleware.process_request(request)
    request.session.save()
    
    # Not skipped yet: should return redirection response
    redirect_response = check_survey_interception(request, collection)
    assert redirect_response is not None
    assert "mandatory=false" in redirect_response.url
    
    # Skip by setting the session key
    session_key = f"skipped_pre_survey_{collection.pk}"
    request.session[session_key] = True
    request.session.save()
    
    # Now check again: should NOT redirect
    no_redirect_response = check_survey_interception(request, collection)
    assert no_redirect_response is None


@pytest.mark.django_db
def test_mandatory_pre_and_post_survey(rf, admin_user):
    survey_pre = Survey.objects.create(name="Mandatory Pre")
    survey_post = Survey.objects.create(name="Mandatory Post")
    collection = CaseCollection.objects.create(
        name="Test Collection",
        pre_survey=survey_pre,
        pre_survey_mandatory=True,
        post_survey=survey_post,
        post_survey_mandatory=True
    )
    
    request = rf.get('/atlas/collection/1/take/')
    request.user = admin_user
    
    # Pre-take interception should happen and pass mandatory=true
    redirect_pre = check_survey_interception(request, collection)
    assert redirect_pre is not None
    assert "mandatory=true" in redirect_pre.url


@pytest.mark.django_db
def test_analytics_filtering(admin_user):
    from django.test import RequestFactory
    from survey.views import survey_results
    
    survey = Survey.objects.create(name="Common Survey")
    q = SurveyQuestion.objects.create(
        survey=survey,
        text="Rate something",
        question_type=SurveyQuestion.QuestionType.INTEGER
    )
    
    collection = CaseCollection.objects.create(name="Collection 1")
    ct = ContentType.objects.get_for_model(collection)
    
    # Response 1: PRE-take
    r1 = SurveyResponse.objects.create(
        survey=survey,
        user=admin_user,
        content_type=ct,
        object_id=collection.pk,
        pre_or_post="PRE"
    )
    SurveyAnswer.objects.create(response=r1, question=q, integer_answer=15)
    
    # Response 2: POST-take
    r2 = SurveyResponse.objects.create(
        survey=survey,
        user=admin_user,
        content_type=ct,
        object_id=collection.pk,
        pre_or_post="POST"
    )
    SurveyAnswer.objects.create(response=r2, question=q, integer_answer=45)
    
    # Requesting results with filter_context='PRE'
    rf = RequestFactory()
    request_pre = rf.get('/survey/results/', {'filter_context': 'PRE'})
    request_pre.user = admin_user
    
    response = survey_results(request_pre, survey.pk)
    # The rendered context should show responses_count = 1, and average_integer = 15.0
    context = response.context_data
    assert context['responses_count'] == 1
    assert context['analytics'][0]['average_integer'] == 15.0
    
    # Requesting results with filter_context='POST'
    request_post = rf.get('/survey/results/', {'filter_context': 'POST'})
    request_post.user = admin_user
    response_post = survey_results(request_post, survey.pk)
    context_post = response_post.context_data
    assert context_post['responses_count'] == 1
    assert context_post['analytics'][0]['average_integer'] == 45.0


