"""This module contains the test cases for the surveys-related api views"""

import json

from django.core.urlresolvers import reverse

from mtp.apps.common.tests.test_cases import MTPTestCase
from mtp.apps.surveys.factories import ChoiceFactory, PoolFactory, QuestionFactory
from mtp.apps.surveys.models import Question


class SurveyViewTestCase(MTPTestCase):

    @classmethod
    def setUpTestData(cls):
        super().setUpTestData()

        cls.pool = PoolFactory(author=cls.trainer)

        cls.single_choice_question = QuestionFactory(
            question_type=Question.QUESTION_TYPES.SINGLE_CHOICE,
            pool=cls.pool
        )
        ChoiceFactory.create_batch(5, question=cls.single_choice_question)

        cls.multi_choices_question = QuestionFactory(
            question_type=Question.QUESTION_TYPES.MULTIPLE_CHOICES,
            pool=cls.pool
        )
        ChoiceFactory.create_batch(5, question=cls.multi_choices_question)

        cls.open_question = QuestionFactory(
            question_type=Question.QUESTION_TYPES.OPEN,
            pool=cls.pool
        )

        # Simulate one single choice answer, two for a multi choices, and text for an open question.
        cls.correct_data = [
            {
                'question_id': cls.single_choice_question.pk,
                'answer_id': cls.single_choice_question.choices.first().pk,
                'text': '',
            },
            {
                'question_id': cls.multi_choices_question.pk,
                'answer_id': cls.multi_choices_question.choices.all()[1].pk,
                'text': '',
            },
            {
                'question_id': cls.multi_choices_question.pk,
                'answer_id': cls.multi_choices_question.choices.all()[2].pk,
                'text': '',
            },
            {
                'question_id': cls.open_question.pk,
                'answer_id': '',
                'text': 'dummy text',
            }
        ]

    def test_post_correct_survey_should_work(self):

        # Post all data as POST, in the ``data`` entry of a ``json`` named POST entry.
        self.login_as_trainee()
        url = reverse('api:survey', kwargs={'session_uuid': self.training_session.pk})
        response = self.client.post(url, {'json': json.dumps({'data': self.correct_data})})

        # We should get a 200.
        self.assertEqual(response.status_code, 200)

        # Now, check our answers.
        all_answers = self.trainees[0].answer_set.filter(training_session=self.training_session)
        self.assertQuerysetEqual(
            all_answers,
            [
                self.single_choice_question.pk,
                self.multi_choices_question.pk,
                self.open_question.pk
            ],
            transform=lambda obj: obj.question_id,
            ordered=False
        )

        answer_single = all_answers.get(question=self.single_choice_question)
        self.assertQuerysetEqual(
            answer_single.choices.all(),
            [self.single_choice_question.choices.first().pk],
            transform=lambda obj: obj.id,
            ordered=False
        )
        self.assertFalse(answer_single.text)

        answer_multi = all_answers.get(question=self.multi_choices_question)
        self.assertQuerysetEqual(
            answer_multi.choices.all(),
            [choice.pk for choice in self.multi_choices_question.choices.all()[1:3]],
            transform=lambda obj: obj.id,
            ordered=False
        )
        self.assertFalse(answer_single.text)

        answer_open = all_answers.get(question=self.open_question)
        self.assertEqual(answer_open.choices.count(), 0)
        self.assertEqual(answer_open.text, 'dummy text')

    def test_post_invalid_data_should_be_ignored(self):

        # Add more data in DB.
        single_choice_questions = QuestionFactory.create_batch(
            4, question_type=Question.QUESTION_TYPES.SINGLE_CHOICE, pool=self.pool)
        for question in single_choice_questions:
            ChoiceFactory.create_batch(5, question=question)

        multi_choices_questions = QuestionFactory.create_batch(
            3, question_type=Question.QUESTION_TYPES.MULTIPLE_CHOICES, pool=self.pool)
        for question in multi_choices_questions:
            ChoiceFactory.create_batch(5, question=question)

        open_question = QuestionFactory(question_type=Question.QUESTION_TYPES.OPEN, pool=self.pool)

        # Add some invalid data, mixing them with valid ones.
        data = [
            # No choices for single choice question.
            {
                'question_id': single_choice_questions[0].pk,
                'answer_id': '',
                'text': '',
            },
            # Many choices for single choice question.
            {
                'question_id': single_choice_questions[1].pk,
                'answer_id': single_choice_questions[1].choices.all()[1].pk,
                'text': '',
            },
            {
                'question_id': single_choice_questions[1].pk,
                'answer_id': single_choice_questions[1].choices.all()[2].pk,
                'text': '',
            },
            # Here we insert a valid answer.
            self.correct_data[0],
            # No choices for multi choices question.
            {
                'question_id': multi_choices_questions[0].pk,
                'answer_id': '',
                'text': '',
            },
            # Text for single choice question.
            {
                'question_id': single_choice_questions[2].pk,
                'answer_id': single_choice_questions[2].choices.first().pk,
                'text': 'dummy text',
            },
            # Text for multi choices question.
            {
                'question_id': multi_choices_questions[1].pk,
                'answer_id': multi_choices_questions[1].choices.all()[1].pk,
                'text': 'dummy text',
            },
            # Here we insert a valid answer.
            self.correct_data[1],
            # Choice from another question for single choice question.
            {
                'question_id': single_choice_questions[3].pk,
                'answer_id': multi_choices_questions[0].choices.all()[1].pk,
                'text': '',
            },
            # Choice from another question for multi choices question.
            {
                'question_id': multi_choices_questions[2].pk,
                'answer_id': single_choice_questions[0].choices.all()[1].pk,
                'text': '',
            },
            # Choices for open question
            {
                'question_id': open_question.pk,
                'answer_id': single_choice_questions[1].choices.all()[1].pk,
                'text': '',
            },
            # Then we add the other valid answers.
        ] + self.correct_data[2:]

        # Post all data as POST, in the ``data`` entry of a ``json`` named POST entry.
        self.login_as_trainee()
        url = reverse('api:survey', kwargs={'session_uuid': self.training_session.pk})
        response = self.client.post(url, {'json': json.dumps({'data': data})})

        # We should get a 200.
        self.assertEqual(response.status_code, 200)

        # And three answers: we should only have the correct ones.
        all_answers = self.trainees[0].answer_set.filter(training_session=self.training_session)
        self.assertQuerysetEqual(
            all_answers,
            [
                self.single_choice_question.pk,
                self.multi_choices_question.pk,
                self.open_question.pk
            ],
            transform=lambda obj: obj.question_id,
            ordered=False
        )
