"""This module holds the test cases related to the serializers of the ``ideas`` app"""

from mock import patch

from rest_framework.serializers import DateTimeField

from mtp.apps.ideas.factories import (
    BrainstormingTagFactory,
    QuestionWallIdeaFactory,
    WordCloudIdeaFactory,
)
from mtp.apps.ideas.models import (
    Brainstorming,
    BrainstormingIdea,
    BrainstormingTag,
    QuestionWall,
    QuestionWallIdea,
    WordCloud,
    WordCloudIdea,
)
from mtp.apps.ideas.tests.test_cases import IdeasTestCase

from ..serializers import (
    BrainstormingIdeaSerializer,
    BrainstormingTagSerializer,
    BrainstormingSerializer,
    QuestionWallIdeaSerializer,
    QuestionWallSerializer,
    WordCloudIdeaSerializer,
    WordCloudSerializer,
)


class BrainstormingSerializersTestCase(IdeasTestCase):
    """Test case for the ``Serializer``s related to the ``Brainstorming`` model"""

    def test_brainstorming_tag_serializer_from_instance_should_work(self):
        """Test the output of a ``BrainstormingTagSerializer``"""

        data = BrainstormingTagSerializer(self.brainstorming_tag).data

        self.assertEqual(
            data,
            {
                'id': self.brainstorming_tag.id,
                'name': self.brainstorming_tag.name,
                'color': self.brainstorming_tag.color,
                'session': self.brainstorming_tag.session_id,
                'brainstorming': self.brainstorming_tag.brainstorming_id,
                'sort_order': self.brainstorming_tag.sort_order
            }
        )

    def test_brainstorming_tag_serializer_from_data_should_work(self):
        """Test creating a ``BrainstormingTag`` from a ``BrainstormingTagSerializer``"""

        data = {
            'name': 'New tag name',
            'color': '#cdcdcd',
            'session': self.training_session.id,
            'brainstorming': self.brainstorming.id
        }

        serializer = BrainstormingTagSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # Check that the data is correct
        new_tag = BrainstormingTag.objects.get(name='New tag name')
        self.assertEqual(new_tag.session, self.training_session)
        self.assertEqual(new_tag.brainstorming, self.brainstorming)
        self.assertEqual(new_tag.color, '#cdcdcd')

    def test_brainstorming_idea_serializer_from_instance_should_work(self):
        """Test the output of a ``BrainstormingIdeaSerializer``"""

        data = BrainstormingIdeaSerializer(self.brainstorming_idea).data

        self.assertEqual(
            data,
            {
                'id': self.brainstorming_idea.id,
                'text': self.brainstorming_idea.text,
                'session': self.brainstorming_idea.session_id,
                'brainstorming': self.brainstorming_idea.brainstorming_id,
                'user': self.brainstorming_idea.user_id,
                'tags': [
                    tag.id
                    for tag in self.brainstorming_idea.tags.non_deleted()
                ],
                'likes': [],
                'created': DateTimeField().to_representation(self.brainstorming_idea.created)
            }
        )

    def test_brainstorming_idea_serializer_from_data_without_tags_should_work(self):
        """Test creating a ``BrainstormingIdea`` from a ``BrainstormingIdeaSerializer``"""

        data = {
            'text': 'New idea',
            'session': self.training_session.id,
            'brainstorming': self.brainstorming.id,
            'user': self.trainee.id,
            'tags': []
        }

        serializer = BrainstormingIdeaSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # Check that the data is correct
        new_idea = BrainstormingIdea.objects.get(text='New idea')
        self.assertEqual(new_idea.session, self.training_session)
        self.assertEqual(new_idea.brainstorming, self.brainstorming)
        self.assertEqual(new_idea.user, self.trainee)

    def test_brainstorming_idea_serializer_from_data_with_tags_should_work(self):
        """Test creating a ``BrainstormingIdea`` from a ``BrainstormingIdeaSerializer``"""

        new_tag = BrainstormingTagFactory(name='New tag', brainstorming=self.brainstorming)

        data = {
            'text': 'New idea',
            'session': self.training_session.id,
            'brainstorming': self.brainstorming.id,
            'user': self.trainee.id,
            'tags': [
                new_tag.id
            ]
        }

        serializer = BrainstormingIdeaSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # Check that the data is correct
        new_idea = BrainstormingIdea.objects.get(text='New idea')
        self.assertEqual(new_idea.session, self.training_session)
        self.assertEqual(new_idea.brainstorming, self.brainstorming)
        self.assertEqual(new_idea.user, self.trainee)
        self.assertEqual(new_idea.tags.count(), 1)
        self.assertEqual(new_idea.tags.first().name, 'New tag')

    def test_brainstorming_idea_serializer_from_data_should_call_broker_hook(self):
        """Test creating a ``BrainstormingIdea`` from a ``BrainstormingIdeaSerializer``"""

        new_tag = BrainstormingTagFactory(name='New tag', brainstorming=self.brainstorming)

        data = {
            'text': 'New idea',
            'session': self.training_session.id,
            'brainstorming': self.brainstorming.id,
            'user': self.trainee.id,
            'tags': [
                new_tag.id
            ]
        }

        serializer = BrainstormingIdeaSerializer(data=data)
        serializer.is_valid()

        with patch('mtp.apps.broker_models_hooks.tasks.publish_to_broker.delay') as mocked:
            new_idea = serializer.save()

        mocked.assert_called_with(
            new_idea.get_serialized_representation(),
            new_idea.get_broker_topic(),
            'UPDATE'
        )

    def test_brainstorming_serializer_from_instance_should_work(self):
        """Test that loading a ``BrainstormingSerializer`` from a ``Brainstorming`` should work"""

        data = BrainstormingSerializer(self.brainstorming).data

        self.assertEqual(
            data,
            {
                'id': self.brainstorming.id,
                'name': self.brainstorming.name,
                'description': self.brainstorming.description,
                'sort_order': self.brainstorming.sort_order,
                'training': self.brainstorming.training_id,
                'session': self.brainstorming.session_id,
                'activity_type': self.brainstorming.activity_type,
                'is_anonymous': self.brainstorming.is_anonymous
            }
        )

    def test_brainstorming_serializer_from_data_should_work(self):
        """Test creating a ``Brainstorming`` from a ``BrainstormingSerializer``"""

        data = {
            'name': 'New brainstorming',
            'description': 'Brainstorming description',
            'session': self.training_session.id,
            'is_anonymous': True,
        }

        serializer = BrainstormingSerializer(data=data)
        serializer.is_valid()

        self.assertTrue(serializer.is_valid())

        serializer.save()

        # Check that the data is correct
        new_brainstorming = Brainstorming.objects.get(name='New brainstorming')
        self.assertEqual(new_brainstorming.description, 'Brainstorming description')
        self.assertEqual(new_brainstorming.session, self.training_session)
        self.assertEqual(new_brainstorming.is_anonymous, True)


class QuestionWallSerializerTestCase(IdeasTestCase):
    """Test case for the ``Serializer``s related to the ``QuestionWall`` model"""

    def test_questionwall_idea_serializer_from_instance_should_work(self):
        """Test the output of a ``QuestionWallIdeaSerializer``"""

        idea = QuestionWallIdeaFactory(questionwall=self.questionwall)
        data = QuestionWallIdeaSerializer(idea).data

        self.assertEqual(
            data,
            {
                'id': idea.id,
                'text': idea.text,
                'session': idea.session_id,
                'questionwall': idea.questionwall_id,
                'user': idea.user_id,
                'likes': [],
                'created': DateTimeField().to_representation(idea.created)
            }
        )

    def test_questionwall_idea_serializer_from_data_should_work(self):
        """Test that we should be able to create a new ``QuestionWallIdea`` with the serializer"""

        # At first, 0 ideas
        self.assertEqual(QuestionWallIdea.objects.count(), 0)

        data = {
            'text': 'questionwall_text',
            'session': self.training_session.id,
            'questionwall': self.questionwall.id,
            'user': self.trainee.id,
        }

        serializer = QuestionWallIdeaSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # We got our new idea created, with correct attributes
        new_idea = QuestionWallIdea.objects.get(text='questionwall_text')

        self.assertEqual(new_idea.session, self.training_session)
        self.assertEqual(new_idea.questionwall, self.questionwall)
        self.assertEqual(new_idea.user, self.trainee)

    def test_questionwall_serializer_from_instance_should_work(self):
        """Test the output of the ``QuestionWallSerializer``"""

        data = QuestionWallSerializer(self.questionwall).data

        self.assertEqual(
            data,
            {
                'id': self.questionwall.id,
                'name': self.questionwall.name,
                'description': self.questionwall.description,
                'sort_order': self.questionwall.sort_order,
                'training': self.questionwall.training_id,
                'session': self.questionwall.session_id,
                'activity_type': self.questionwall.activity_type,
                'is_anonymous': self.questionwall.is_anonymous
            }
        )

    def test_questionwall_serializer_from_data_should_work(self):
        """Test that we should be able to create a new ``QuestionWall`` using the serializer"""

        data = {
            'name': 'New questionwall',
            'description': 'Questionwall description',
            'session': self.training_session.id,
            'is_anonymous': True,
        }

        serializer = QuestionWallSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # Check that the data is correct
        new_questionwall = QuestionWall.objects.get(name='New questionwall')
        self.assertEqual(new_questionwall.description, 'Questionwall description')
        self.assertEqual(new_questionwall.session, self.training_session)
        self.assertEqual(new_questionwall.is_anonymous, True)


class WordCloudSerializerTestCase(IdeasTestCase):
    """Test case for the ``Serializer``s related to the ``WordCloud`` model"""

    def test_wordcloud_idea_serializer_from_instance_should_work(self):
        """Test the output of a ``WordCloudIdeaSerializer``"""

        idea = WordCloudIdeaFactory(wordcloud=self.wordcloud)
        data = WordCloudIdeaSerializer(idea).data

        self.assertEqual(
            data,
            {
                'id': idea.id,
                'text': idea.text,
                'session': idea.session_id,
                'wordcloud': idea.wordcloud.id,
                'user': idea.user_id,
                'likes': [],
                'created': DateTimeField().to_representation(idea.created)
            }
        )

    def test_wordcloud_idea_serializer_from_data_should_work(self):
        """Test that we should be able to create a new ``WordCloudIdea`` with the serializer"""

        # At first, 0 ideas
        self.assertEqual(WordCloudIdea.objects.count(), 0)

        data = {
            'text': 'wordcloud_text',
            'session': self.training_session.id,
            'wordcloud': self.wordcloud.id,
            'user': self.trainee.id,
        }

        serializer = WordCloudIdeaSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # We got our new idea created, with correct attributes
        new_idea = WordCloudIdea.objects.get(text='wordcloud_text')

        self.assertEqual(new_idea.session, self.training_session)
        self.assertEqual(new_idea.wordcloud, self.wordcloud)
        self.assertEqual(new_idea.user, self.trainee)

    def test_wordcloud_serializer_from_instance_should_work(self):
        """Test the output of the ``WordCloudSerializer``"""

        data = WordCloudSerializer(self.wordcloud).data

        self.assertEqual(
            data,
            {
                'id': self.wordcloud.id,
                'name': self.wordcloud.name,
                'description': self.wordcloud.description,
                'sort_order': self.wordcloud.sort_order,
                'training': self.wordcloud.training_id,
                'session': self.wordcloud.session_id,
                'activity_type': self.wordcloud.activity_type,
                'is_anonymous': self.wordcloud.is_anonymous
            }
        )

    def test_wordcloud_serializer_from_data_should_work(self):
        """Test that we should be able to create a new ``WordCloud`` using the serializer"""

        data = {
            'name': 'New wordcloud',
            'description': 'WordCloud description',
            'session': self.training_session.id,
            'is_anonymous': True,
        }

        serializer = WordCloudSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        serializer.save()

        # Check that the data is correct
        new_wordcloud = WordCloud.objects.get(name='New wordcloud')
        self.assertEqual(new_wordcloud.description, 'WordCloud description')
        self.assertEqual(new_wordcloud.session, self.training_session)
        self.assertEqual(new_wordcloud.is_anonymous, True)
