"""Test cases for the ``workshops`` models."""

from .test_cases import WorkshopTestCase


class WorkshopModelTestCase(WorkshopTestCase):
    """Test cases for the ``Workshop`` model."""

    def get_trainee_score(self):
        """Shortcut method to get the score fo the trainee for the current workshop"""

        try:
            # Delete the ``@cached_property`` from the workshop, that's necessary
            # to get the right parts attributes
            del self.workshop.assessing_parts
        except AttributeError:
            pass  # Do nothing, the attribute might not be set

        return self.workshop.compute_challenge_score(
            session=self.training_session, trainee=self.trainee)

    def test_compute_challenge_score_single_choice_with_valid_answer(self):
        """Test the ``compute_challenge_score`` method with a single choice question"""

        answer = self.workshop_question.answers.filter(is_correct=True).first()

        # Add a valid user answer
        self.add_user_answers([answer])

        # The trainee got the points for this question
        self.assertEqual(self.get_trainee_score(), 1)

    def test_compute_challenge_score_single_choice_with_invalid_answer(self):
        """Test the ``compute_challenge_score`` method with a single choice question"""

        answer = self.workshop_question.answers.filter(is_correct=False).first()

        # Add a invalid user answer
        self.add_user_answers([answer])

        # The trainee got the points for this question (0)
        self.assertEqual(self.get_trainee_score(), 0)

    def test_compute_challenge_score_multiple_choice_answer_all_valid(self):
        """Test the ``compute_challenge_score`` method with a multiple choices question"""

        # The trainee found all (and only) the valid answers
        answers = self.workshop_question_mc.answers.filter(is_correct=True)

        # Add all valid answers
        self.add_user_answers(answers)

        # The trainee got the points for this question (1+1)
        self.assertEqual(self.get_trainee_score(), 2)

    def test_compute_challenge_score_multiple_choice_answer_one_invalid(self):
        """Test the ``compute_challenge_score`` method with a multiple choices question

        In this test, the ``is_all_or_nothing`` flag is set to True.

        """

        # The trainee found all the answers (valid AND invalid ones)
        answers = self.workshop_question_mc.answers.all()

        # Add all answers
        self.add_user_answers(answers)

        # The trainee got nothing since it's a ``all_or_nothing`` question type
        self.assertEqual(self.get_trainee_score(), 0)

    def test_compute_challenge_score_multiple_choice_answer_one_invalid_all_or_nothing_false(self):
        """Test the ``compute_challenge_score`` method with a multiple choices question

        In this test, the ``is_all_or_nothing`` flag is set to False.

        """

        # Deactivate the ``is_all_or_nothing`` flag
        training = self.workshop_question_mc.workshop.training

        with training.override_version_state(training.VERSION_STATES.DRAFT):
            self.workshop_question_mc.is_all_or_nothing = False
            self.workshop_question_mc.save()

        # The trainee found all the answers (valid AND invalid ones)
        answers = self.workshop_question_mc.answers.all()

        # Add all answers
        self.add_user_answers(answers)

        # The trainee got 2 points (for the two valid answers)
        self.assertEqual(self.get_trainee_score(), 2)

    def test_media_files(self):
        """Test that the ``media_files`` property should return a list of media path"""

        self.assertEqual(
            self.workshop.media_files,
            [self.workshop_question_mc_image.image.name]
        )


class WorkshopStepQuestionModelTestCase(WorkshopTestCase):
    """Test cases for the ``WorkshopStepQuestion`` model."""

    @classmethod
    def setUpTestData(cls):
        """Set up the test data"""

        super().setUpTestData()

        cls.valid_answers = cls.workshop_question_mc.answers.filter(is_correct=True)
        cls.invalid_answers = cls.workshop_question_mc.answers.filter(is_correct=False)

    def question_is_valid(self):
        """Shortcut method to test the validity of the question"""

        return self.workshop_question_mc.is_valid_for_trainee(
            self.trainee, self.training_session)

    def test_is_valid_for_trainee_with_all_or_nothing(self):
        """Test the ``is_valid_for_trainee`` method when ``is_all_or_nothing`` flag is active."""

        # Add a valid user answer
        self.add_user_answers([self.valid_answers.first()])

        # Since the question is a multiple choice one, with the ``is_all_or_nothing`` flag,
        # the question is not valid yet
        self.assertFalse(self.question_is_valid())

        # Add another valid user answer
        self.add_user_answers([self.valid_answers.last()])

        # Since the trainee got all the good answers, the question is valid now
        self.assertTrue(self.question_is_valid())

        # Add an invalid answer
        self.add_user_answers([self.invalid_answers.first()])

        # The question should now be invalid
        self.assertFalse(self.question_is_valid())

    def test_is_valid_for_trainee_without_all_or_nothing(self):
        """Test the ``is_valid_for_trainee`` method when ``is_all_or_nothing`` is not active."""

        # Deactivate the ``is_all_or_nothing`` flag
        training = self.workshop_question_mc.workshop.training
        with training.override_version_state(training.VERSION_STATES.DRAFT):

            self.workshop_question_mc.is_all_or_nothing = False
            self.workshop_question_mc.save()

        # Add an invalid answer
        self.add_user_answers([self.invalid_answers.first()])

        # The question should be invalid
        self.assertFalse(self.question_is_valid())

        # Add a valid answer
        self.add_user_answers([self.valid_answers.first()])

        # With at last one good answer, the question is valid
        self.assertTrue(self.question_is_valid())
