from django.db import transaction
from django.test import TestCase, RequestFactory
from graphene.test import Client
from graphql_relay import to_global_id

from api.schema import schema
from books.factories import InstrumentFactory, ContentBlockFactory, ModuleFactory
from notes.models import InstrumentBookmark, ContentBlockBookmark
from users.models import User
from users.services import create_users

UPDATE_INSTRUMENT_BOOKMARK_MUTATION = """
mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {
  updateInstrumentBookmark(input: $input) {
    success
    __typename
  }
}
"""

UPDATE_CONTENT_BLOCK_BOOKMARK_MUTATION = """
mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {
  updateContentBookmark(input: $input) {
    success
  }
}
"""


class DuplicateBookmarksTestCase(TestCase):
    def setUp(self):
        create_users()

        self.student1 = User.objects.get(username='student1')
        self.student2 = User.objects.get(username='student2')
        self.instrument = InstrumentFactory(slug='instrument-slug')
        module = ModuleFactory()
        self.content_block = ContentBlockFactory(contents=[
            {
                'type': 'text_block',
                'value': {
                    'text': 'Ein Text'
                }
            }
        ], module=module)
        self.uuid = '56e45c9b-e0b2-4103-82e0-ad04ba05ac5b'
        self.other_uuid = '56e45c9b-e0b2-4103-82e0-ad04ba05ac5c'
        self.content_block_id = to_global_id('ContentBlockNode', self.content_block.id)

        request = RequestFactory().get('/')
        request.user = self.student1
        self.client = Client(schema=schema, context_value=request)

        request = RequestFactory().get('/')
        request.user = self.student2
        self.client2 = Client(schema=schema, context_value=request)

    def _check_success(self, result, key):
        self.assertIsNone(result.get('errors'))
        self.assertTrue(
            result.get('data').get(key).get('success'))

    def test_two_students_bookmark_the_same_instrument_content(self):
        variables = {
            "input": {
                "bookmarked": True,
                "instrument": self.instrument.slug,
                "uuid": self.uuid
            }
        }

        result1 = self.client.execute(UPDATE_INSTRUMENT_BOOKMARK_MUTATION, variables=variables)
        self._check_success(result1, 'updateInstrumentBookmark')
        self.assertEqual(InstrumentBookmark.objects.count(), 1)

        result2 = self.client2.execute(UPDATE_INSTRUMENT_BOOKMARK_MUTATION, variables=variables)
        self._check_success(result2, 'updateInstrumentBookmark')
        self.assertEqual(InstrumentBookmark.objects.count(), 2)

    def test_two_students_bookmark_the_same_content_block_content(self):
        variables = {
            "input": {
                "bookmarked": True,
                "contentBlock": self.content_block_id,
                "uuid": self.other_uuid
            }
        }

        result1 = self.client.execute(UPDATE_CONTENT_BLOCK_BOOKMARK_MUTATION, variables=variables)
        self._check_success(result1, 'updateContentBookmark')
        self.assertEqual(ContentBlockBookmark.objects.count(), 1)

        result2 = self.client2.execute(UPDATE_CONTENT_BLOCK_BOOKMARK_MUTATION, variables=variables)
        self._check_success(result2, 'updateContentBookmark')
        self.assertEqual(ContentBlockBookmark.objects.count(), 2)

    def test_returns_one_instrument_bookmark(self):
        # create 2 bookmarks for same user and content
        InstrumentBookmark.objects.create(
            instrument=self.instrument,
            uuid=self.uuid,
            user=self.student1
        )

        variables = {
            "input": {
                "bookmarked": True,
                "instrument": self.instrument.slug,
                "uuid": self.uuid
            }
        }

        # need to do this because of a django test quirk, see:
        # https://stackoverflow.com/questions/21458387/transactionmanagementerror-you-cant-execute-queries-until-the-end-of-the-atom
        with transaction.atomic():
            result = self.client.execute(UPDATE_INSTRUMENT_BOOKMARK_MUTATION, variables=variables)
        self._check_success(result, 'updateInstrumentBookmark')
        self.assertEqual(InstrumentBookmark.objects.count(), 1)

    def test_returns_one_content_block_bookmark(self):
        # create 2 bookmarks for same user and content
        ContentBlockBookmark.objects.create(
            content_block=self.content_block,
            uuid=self.other_uuid,
            user=self.student1
        )

        variables = {
            "input": {
                "bookmarked": True,
                "contentBlock": self.content_block_id,
                "uuid": self.other_uuid
            }
        }

        # need to do this because of a django test quirk, see:
        # https://stackoverflow.com/questions/21458387/transactionmanagementerror-you-cant-execute-queries-until-the-end-of-the-atom
        with transaction.atomic():
            result = self.client.execute(UPDATE_CONTENT_BLOCK_BOOKMARK_MUTATION, variables=variables)
        self._check_success(result, 'updateContentBookmark')
        self.assertEqual(ContentBlockBookmark.objects.count(), 1)
