"""
Tests for credit requirement display on the progress page.
"""

import ddt
from django.conf import settings
from django.core.urlresolvers import reverse
from mock import patch

from course_modes.models import CourseMode
from openedx.core.djangoapps.credit import api as credit_api
from openedx.core.djangoapps.credit.models import CreditCourse
from student.tests.factories import CourseEnrollmentFactory, UserFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory


@patch.dict(settings.FEATURES, {"ENABLE_CREDIT_ELIGIBILITY": True})
@ddt.ddt
class ProgressPageCreditRequirementsTest(SharedModuleStoreTestCase):
    """
    Tests for credit requirement display on the progress page.
    """

    USERNAME = "bob"
    PASSWORD = "test"
    USER_FULL_NAME = "Bob"

    MIN_GRADE_REQ_DISPLAY = "Final Grade Credit Requirement"
    VERIFICATION_REQ_DISPLAY = "Midterm Exam Credit Requirement"

    @classmethod
    def setUpClass(cls):
        super(ProgressPageCreditRequirementsTest, cls).setUpClass()
        cls.course = CourseFactory.create()

    def setUp(self):
        super(ProgressPageCreditRequirementsTest, self).setUp()

        # Configure course as a credit course
        CreditCourse.objects.create(course_key=self.course.id, enabled=True)

        # Configure credit requirements (passing grade and in-course reverification)
        credit_api.set_credit_requirements(
            self.course.id,
            [
                {
                    "namespace": "grade",
                    "name": "grade",
                    "display_name": self.MIN_GRADE_REQ_DISPLAY,
                    "criteria": {
                        "min_grade": 0.8
                    }
                },
                {
                    "namespace": "reverification",
                    "name": "midterm",
                    "display_name": self.VERIFICATION_REQ_DISPLAY,
                    "criteria": {}
                }
            ]
        )

        # Create a user and log in
        self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
        self.user.profile.name = self.USER_FULL_NAME
        self.user.profile.save()

        result = self.client.login(username=self.USERNAME, password=self.PASSWORD)
        self.assertTrue(result, msg="Could not log in")

        # Enroll the user in the course as "verified"
        self.enrollment = CourseEnrollmentFactory(
            user=self.user,
            course_id=self.course.id,
            mode="verified"
        )

    def test_credit_requirements_maybe_eligible(self):
        # The user hasn't satisfied any of the credit requirements yet, but she
        # also hasn't failed any.
        response = self._get_progress_page()

        # Expect that the requirements are displayed
        self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY)
        self.assertContains(response, self.VERIFICATION_REQ_DISPLAY)
        self.assertContains(response, "Upcoming")
        self.assertContains(
            response,
            "{}, you have not yet met the requirements for credit".format(self.USER_FULL_NAME)
        )

    def test_credit_requirements_eligible(self):
        """
        Mark the user as eligible for all requirements. Requirements are only displayed
        for credit and verified enrollments.
        """
        credit_api.set_credit_requirement_status(
            self.user, self.course.id,
            "grade", "grade",
            status="satisfied",
            reason={"final_grade": 0.95}
        )

        credit_api.set_credit_requirement_status(
            self.user, self.course.id,
            "reverification", "midterm",
            status="satisfied", reason={}
        )

        # Check the progress page display
        response = self._get_progress_page()
        self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY)
        self.assertContains(response, self.VERIFICATION_REQ_DISPLAY)
        self.assertContains(
            response,
            "{}, you have met the requirements for credit in this course.".format(self.USER_FULL_NAME)
        )
        self.assertContains(response, "Completed by {date}")

        credit_requirements = credit_api.get_credit_requirement_status(self.course.id, self.user.username)
        for requirement in credit_requirements:
            self.assertContains(response, requirement['status_date'].strftime('%Y-%m-%d %H:%M'))
        self.assertNotContains(response, "95%")

    def test_credit_requirements_not_eligible(self):
        """
        Mark the user as having failed both requirements. Requirements are only displayed
        for credit and verified enrollments.
        """
        credit_api.set_credit_requirement_status(
            self.user, self.course.id,
            "reverification", "midterm",
            status="failed", reason={}
        )

        # Check the progress page display
        response = self._get_progress_page()
        self.assertContains(response, self.MIN_GRADE_REQ_DISPLAY)
        self.assertContains(response, self.VERIFICATION_REQ_DISPLAY)
        self.assertContains(
            response,
            "{}, you are no longer eligible for credit in this course.".format(self.USER_FULL_NAME)
        )
        self.assertContains(response, "Verification Failed")

    @ddt.data(
        (CourseMode.VERIFIED, True),
        (CourseMode.CREDIT_MODE, True),
        (CourseMode.HONOR, False),
        (CourseMode.AUDIT, False),
        (CourseMode.PROFESSIONAL, False),
        (CourseMode.NO_ID_PROFESSIONAL_MODE, False)
    )
    @ddt.unpack
    def test_credit_requirements_on_progress_page(self, enrollment_mode, is_requirement_displayed):
        """Test the progress table is only displayed to the verified and credit students."""
        self.enrollment.mode = enrollment_mode
        self.enrollment.save()  # pylint: disable=no-member

        response = self._get_progress_page()
        # Verify the requirements are shown only if the user is in a credit-eligible mode.
        classes = ('credit-eligibility', 'eligibility-heading')
        method = self.assertContains if is_requirement_displayed else self.assertNotContains

        for _class in classes:
            method(response, _class)

    def _get_progress_page(self):
        """Load the progress page for the course the user is enrolled in. """
        url = reverse("progress", kwargs={"course_id": unicode(self.course.id)})
        return self.client.get(url)
