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

from mtp.apps.accounts.constants import INTERNAL_GROUP_TRAINEE, INTERNAL_GROUP_TRAINER
from mtp.apps.common.tests.perf_rec import without_perf_rec

from .test_cases import WorkshopTestCase
from ..models import WorkshopStepQuestion
from ..serializers import CompatibilityWorkshopSerializer, CompatibilityWorkshopStepImageSerializer


class CompatibilityWorkshopSerializerTestCases(WorkshopTestCase):
    """Tests the workshop compatibility serializers behaviour."""

    @classmethod
    def setUpTestData(cls):
        """Set the training to DRAFT, so we can easily change stuff."""

        super().setUpTestData()

        cls.training.version_state = cls.training.VERSION_STATES.DRAFT
        cls.training.save()

    def get_serialized_workshop(self):
        """Shortcut method to get a serialized workshop."""

        return CompatibilityWorkshopSerializer(self.workshop).data

    def test_workshop_is_not_broadcastable(self):
        """Test the serialized workshop when ``is_broadcastable`` is ``False``"""

        # Make the workshop not broadcastable
        self.workshop.is_broadcastable = False
        self.workshop.save()

        # The workshop is NOT broadcastable
        self.assertEqual(self.workshop.is_broadcastable, False)

        serialized_workshop = self.get_serialized_workshop()

        # The workshop got a correct "module" property
        self.assertEqual(
            serialized_workshop['module'],
            'workshop'
        )

        # The serialized workshop type is correct
        self.assertEqual(
            serialized_workshop['type'],
            'workshop'
        )

        # We got on
        self.assertCountEqual(
            serialized_workshop['groups'],
            [INTERNAL_GROUP_TRAINEE, INTERNAL_GROUP_TRAINER]
        )

    def test_workshop_is_broadcastable(self):
        """Test the serialized workshop when ``is_broadcastable`` is ``True``"""

        # Make the workshop broadcastable
        self.workshop.is_broadcastable = True
        self.workshop.save()

        # The workshop is broadcastable
        self.assertEqual(self.workshop.is_broadcastable, True)

        serialized_workshop = self.get_serialized_workshop()

        # The serialized workshop type is correct
        self.assertEqual(
            serialized_workshop['type'],
            'livevoting'
        )

        self.assertCountEqual(
            serialized_workshop['groups'],
            [INTERNAL_GROUP_TRAINER]
        )

    def test_workshop_is_steps_order_random_is_false(self):
        """Test the workshop steps order when the ``is_steps_order_random`` workshop
        attribute is False."""

        serialized_workshop = self.get_serialized_workshop()
        for idx, question in enumerate(serialized_workshop['questions']):
            self.assertEqual(question['order'], idx + 1)

    @without_perf_rec
    def test_workshop_is_steps_order_random_is_true(self):
        """Test the workshop steps order when the ``is_steps_order_random`` workshop
        attribute is True.

        Notes
        -----
        Since the random can shuffle the steps on their initial order, we need to test
        multiple times the result.

        """

        self.workshop.is_steps_order_random = True

        # We iterate until we have a different order than the initial one
        different_result = False
        current_orders = None
        for __ in range(0, 10):
            previous_orders = current_orders
            current_orders = [
                (question['order'] == idx + 1)
                for idx, question in enumerate(self.get_serialized_workshop()['questions'])
            ]
            if not previous_orders or current_orders == previous_orders:
                continue
            different_result = True
            break

        self.assertTrue(different_result)

    def test_workshop_question_is_answers_order_random_is_false(self):
        """Test the workshop answers order when the ``is_answers_order_random``
        workshop attribute is False."""

        self.workshop.is_steps_order_random = False

        ws_question_json = self.get_serialized_workshop()['questions'][0]
        for idx, question in enumerate(ws_question_json['answers']):
            self.assertEqual(question['order'], idx + 1)

    @without_perf_rec
    def test_workshop_question_is_answers_order_random_is_true(self):
        """Test the workshop steps order when the ``is_answers_order_random``
        workshop attribute is True.

        Notes
        -----
        Since the random can shuffle the answers on their initial order, we need to test
        multiple times the result.

        """

        question = self.workshop.steps.instance_of(
            WorkshopStepQuestion).order_by('sort_order').first()
        question.is_answers_order_random = True
        question.save()

        # We iterate until we have a different order than the initial one
        different_result = False
        current_orders = None

        # Increment this number each time the test fail caused by the ~randomness
        test_occurrences = 13

        for __ in range(0, test_occurrences):
            previous_orders = current_orders
            current_orders = [
                answer['order']
                for idx, answer in enumerate(
                    self.get_serialized_workshop()['questions'][0]['answers'])
            ]
            if not previous_orders or current_orders == previous_orders:
                continue
            different_result = True
            break

        self.assertTrue(different_result)

    @without_perf_rec
    def test_workshop_question_is_questions_answers_order_random_is_true(self):
        """Test the workshop steps order when the ``is_questions_answers_order_random``
        workshop attribute is True.

        Notes
        -----
        Since the random can shuffle the answers on their initial order, we need to test
        multiple times the result.

        """

        self.workshop.is_questions_answers_order_random = True
        self.workshop.save()

        # We iterate until we have a different order than the initial one
        different_result = False
        current_orders = None

        # Increment this number each time the test fail caused by the ~randomness
        test_occurrences = 11

        for __ in range(0, test_occurrences):
            previous_orders = current_orders
            current_orders = [
                answer['order']
                for idx, answer in enumerate(
                    self.get_serialized_workshop()['questions'][0]['answers'])
            ]
            if not previous_orders or current_orders == previous_orders:
                continue
            different_result = True
            break

        self.assertTrue(different_result)


class CompatibilityWorkshopStepImageSerializerTestCases(WorkshopTestCase):
    """Tests the workshop step image compatibility serializers behaviour."""

    def test_workshop_step_image_serialization(self):
        """Test the serialization of a workshop step image."""
        data = CompatibilityWorkshopStepImageSerializer(self.workshop_question_mc_image).data

        self.assertEqual(
            data['description'],
            self.workshop_question_mc_image.image.url
        )
        self.assertEqual(
            data['label'],
            self.workshop_question_mc_image.title
        )
        self.assertEqual(
            data['order'],
            self.workshop_question_mc_image.sort_order
        )
