import json
import random

from collaborators.models import Access
from institute.models import Institute
from plan.models import Environment
from question_bank.models import QuestionBank, QuestionBankDefaultIcon
from wikiazma.myTest import MyTestCase


class QuestionBankTest(MyTestCase):

    def setUp(self):
        self.setUpHelpers()
        self.setBaseUser()

        Environment.objects.update(default_max_institutes_per_user=100, default_max_collaborators_per_institute=100)
        self.institute = self.instituteHelper.create_institute(name="unit_test_institute")

        # (self.second_user, self.second_user_token) = self.authenticateHelper.new_user_with_email()

    def tearDown(self):
        self.instituteHelper.delete_institute(institute_id=self.institute["id"])
        self.user.delete()  # Institute.objects.filter(user=self.second_user).delete()  # self.second_user.delete()

    def test_create_question_bank(self):
        # success
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'name': 'my_question_bank'})
        self.assertEqual('ok', response_data['status'], error_message)
        # (response_data, status_code, error_message) = self.post_with_token(
        #     self.questionbankHelper.create_question_bank_url, {
        #         'institute_id': self.institute['id'],
        #         'name': 'my_question_bank'
        #     })
        # self.assertEqual('error', response_data['status'], error_message)
        # self.assertEqual('you have already a question bank with this name', response_data['message'], error_message)
        #############################################################################################

        with open('test_files/image.png', 'rb') as fp1:
            (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                               {'context_institute_id': self.institute['id'],
                                                                                'name': 'my_question_bank_icon', 'icon': fp1})
            self.assertEqual('ok', response_data['status'],
                             error_message)  # self.assertEqual('my_question_bank_icon', response_data['data']['question_bank']['name'], error_message)
        # error: invalid institute_id
        question_bank_default_icon = QuestionBankDefaultIcon.objects.create(icon="/image/test")
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'name': 'my_question_bank_icon_id',
                                                                            'default_icon_id': question_bank_default_icon.id})

        self.assertEqual('ok', response_data['status'], error_message)

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'name': 'my_question_bank12'})
        self.assertEqual('ok', response_data['status'], error_message)

    def test_create_question_bank_error(self):
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {
                                                                               'context_institute_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'name': 'my_question_bank'})
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)

        # error: expired token
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'name': 'my_question_bank'},
                                                                           test_token=self.expired_token)
        self.assertIn('Authorization failed', response_data['message'], error_message)

        # serializer error
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': '',
                                                                            'name': 'my_question_bank'})
        self.assertEqual('validation_error', response_data['status'], error_message)

        # serializer error
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'name': ''})
        self.assertEqual('validation_error', response_data['status'], error_message)

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'name': 'my_question_bank_icon_id',
                                                                            'default_icon_id': 'ea915429-dfdc-4605-be15-5cf82fbd823d'})

        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('question_bank_default_icon not found', response_data['message'], error_message)

    def test_edit_question_bank_error(self):
        # invalid question_bank_id
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {
                                                                               'question_bank_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'name': 'my_new_name'})
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)

        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank',
                                                                        public=True)

        # you can not change a public question_bank to private
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'public': False})
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertIn('question_bank', response_data['data'], error_message)

        # expired token
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'name': 'my_name'}, test_token=self.expired_token)
        self.assertIn('Authorization failed', response_data['message'], error_message)

        # serializer error
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': '', 'name': 'my_name'})
        self.assertEqual('validation_error', response_data['status'], error_message)

        # you cannot edit a public question bank that is not yours although you have read permission
        # #70274207 testing a __PERMISSION_WRITE_QUESTIONBANK__ on public question banks
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="ahmad3@yahoo.com", password='dEdhbd3Ethdset')
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'name': 'my_name'}, test_token=user2_token)
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)

    def test_edit_question_bank_success(self):
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank',
                                                                        description='qb_description')

        # no field was sent
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id, })
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('my_question_bank', response_data['data']['question_bank']['name'], error_message)
        question_bank_default_icon = QuestionBankDefaultIcon.objects.create(icon="/image/test")
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'default_icon_id': question_bank_default_icon.id})
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'default_icon_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363'})
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('question_bank_default_icon not found', response_data['message'], error_message)
        with open('test_files/image.png', 'rb') as fp1:
            (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                               {'question_bank_id': question_bank_id,
                                                                                'icon': fp1})
            self.assertEqual('ok', response_data['status'], error_message)
            self.assertEqual('my_question_bank', response_data['data']['question_bank']['name'], error_message)
        # name and description sent
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'name': 'my_new_name',
                                                                            'description': 'new_qb_description', 'public': True})
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('my_new_name', response_data['data']['question_bank']['name'], error_message)
        self.assertEqual('new_qb_description', response_data['data']['question_bank']['description'], error_message)
        self.assertEqual('public', response_data['data']['question_bank']['accessibility'], error_message)

        # empty description sent
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'description': '', 'public': True})
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('', response_data['data']['question_bank']['description'], error_message)

    def test_edit_question_bank_filters_template_success(self):
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'])

        self.questionHelper.create_questions_with_real_tags(question_bank_id)

        filters_template = [
            {
                'key': 'فصل',
                'children': [
                    {
                        'key': 'درس',
                        'children': []
                    }
                ]
            }
        ]
        expected_filters = [
            {"key": "فصل", "order": 0, "stock": 8,
             "values": [
                 {"value": "1", "stock": 4, "order": 0,
                  "children": [
                      {"key": "درس", "order": 0, "stock": 4,
                       "values": [
                           {"value": "1", "stock": 1, "order": 0, "children": []},
                           {"value": "2", "stock": 2, "order": 1, "children": []},
                           {"value": "3", "stock": 1, "order": 2, "children": []}]
                       }
                  ]},
                 {"value": "2", "stock": 4, "order": 1,
                  "children": [
                      {"key": "درس", "order": 0, "stock": 4,
                       "values": [
                           {"value": "1", "stock": 1, "order": 0, "children": []},
                           {"value": "2", "stock": 2, "order": 1, "children": []},
                           {"value": "4", "stock": 1, "order": 2, "children": []}]
                       }
                  ]}
             ]}
        ]
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.edit_question_bank_filters_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'filters_template': json.dumps(filters_template)})
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertIn('filters', response_data['data']['question_bank'], error_message)
        self.assertEqual(expected_filters, response_data['data']['question_bank']['filters'], error_message)

    def test_delete_question_bank(self):
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank')

        # error: invalid question_bank_id
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.archive_question_bank_url,
                                                                           {
                                                                               'question_bank_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'context_institute_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363', })
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)

        # error: expired token
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.archive_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'context_institute_id': self.institute['id'], },
                                                                           test_token=self.expired_token)
        self.assertIn('Authorization failed', response_data['message'], error_message)

        # error: serializer
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.archive_question_bank_url,
                                                                           {'question_bank_id': '',
                                                                            'context_institute_id': self.institute['id']})
        self.assertEqual('validation_error', response_data['status'], error_message)

        # success
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.archive_question_bank_url,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'context_institute_id': self.institute['id'], })
        self.assertEqual('ok', response_data['status'], error_message)
        question_bank = QuestionBank.objects.get(id=question_bank_id)
        self.assertEqual(True, question_bank.archived, error_message)

    def test_question_bank_get_user(self):
        ################caller######################################
        (self.caller, self.caller_token) = self.authenticateHelper.new_user_with_email(email="caller@nisodynamic.com")

        self.institute_caller = Institute.objects.create(user=self.caller, name='caller', logo='image/test/image.png')

        Access.objects.create(user=self.caller, institute=self.institute_caller, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_caller.name)
        #################target#####################################
        (self.target, self.target_token) = self.authenticateHelper.new_user_with_email(email="target@nisodynamic.com")
        self.institute_target = Institute.objects.create(user=self.target, name='target')
        Access.objects.create(user=self.target, institute=self.institute_target, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_target.name)

        ######################################################################################
        question_bank_public = QuestionBank.objects.create(institute=self.institute_target, name='public', accessibility='public')
        ######################################################################################
        question_bank_private = QuestionBank.objects.create(institute=self.institute_target, name='private',
                                                            accessibility='private')
        ####################################################################################################
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute_target.id,
                                                                            'question_bank_id': question_bank_private.id, },
                                                                           test_token=self.target_token)
        self.assertEqual('ok', response_data['status'], error_message)
        #####################################################################################
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute_target.id,
                                                                            'question_bank_id': question_bank_public.id, },
                                                                           test_token=self.target_token)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertIn('tags', response_data['data']['question_bank'], error_message)
        self.assertIn('filters', response_data['data']['question_bank'], error_message)

        ######################################################################################

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute_caller.id,
                                                                            'question_bank_id': question_bank_public.id, },
                                                                           test_token=self.caller_token)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('Successful', response_data['message'], error_message)

        ######################################################################################

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute_caller.id,
                                                                            'question_bank_id': question_bank_private.id, },
                                                                           test_token=self.caller_token)
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)
        ######################################################################################
        # QuestionBankAccessibility.objects.create(institute=self.institute_caller, question_bank=question_bank_private, type='ownership',
        #                                          question_bank_name=question_bank_private.name)

        self.institute_caller.subscribe_qb(question_bank_private.pk)
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute_caller.id,
                                                                            'question_bank_id': question_bank_private.id, },
                                                                           test_token=self.caller_token)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('Successful', response_data['message'], error_message)

    def test_get_question_bank_success(self):

        # private question bank
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank')

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'question_bank_id': question_bank_id, })
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('my_question_bank', response_data['data']['question_bank']['name'], error_message)

        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank_new')

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'question_bank_id': question_bank_id, })
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('my_question_bank_new', response_data['data']['question_bank']['name'], error_message)
        # self.assertEqual(
        #     True, response_data['data']['question_bank']['picked'], error_message)
        # self.assertEqual(
        #     'ownership', response_data['data']['question_bank']['relation'], error_message)
        (self.caller, self.caller_token) = self.authenticateHelper.new_user_with_email(email="caller@nisodynamic.com")

        self.institute_caller = Institute.objects.create(user=self.caller, name='caller', logo='image/test/image.png')

        Access.objects.create(user=self.caller, institute=self.institute_caller, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_caller.name)
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank_test_picked',
                                                                        public=True)

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute_caller.id,
                                                                            'question_bank_id': question_bank_id, },
                                                                           test_token=self.caller_token)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('my_question_bank_test_picked', response_data['data']['question_bank']['name'], error_message)
        # self.assertEqual(
        #     False, response_data['data']['question_bank']['picked'], error_message)
        # self.assertEqual(
        #     None, response_data['data']['question_bank']['relation'], error_message)

        # public question bank
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], public=True,
                                                                        name='public_question_bank')

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'question_bank_id': question_bank_id, })
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('public_question_bank', response_data['data']['question_bank']['name'], error_message)

        # get a public question bank that we do not have direct access to
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="ahmad3@yahoo.com", password='dEdhbd3Ethdset')
        institute = Institute.objects.get(user=user2)
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'context_institute_id': institute.id, },
                                                                           test_token=user2_token)

        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual('public_question_bank', response_data['data']['question_bank']['name'], error_message)

    def test_get_question_bank_error(self):
        # invalid question_bank_id
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {
                                                                               'question_bank_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'context_institute_id': self.institute['id'], })
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)

        # serializer
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'question_bank_id': '',
                                                                            'context_institute_id': self.institute['id'], })
        self.assertEqual('validation_error', response_data['status'], error_message)

        # expired token
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank')
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'context_institute_id': self.institute['id'], },
                                                                           test_token=self.expired_token)
        self.assertIn('Authorization failed', response_data['message'], error_message)

        # get a private question bank that we do not have direct access to
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="ahmad3@yahoo.com", password='dEdhbd3Ethdset')
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'question_bank_id': question_bank_id,
                                                                            'context_institute_id': self.institute['id'], },
                                                                           test_token=user2_token)
        self.assertEqual('Forbidden', response_data['message'], error_message)

        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], public=True,
                                                                        name='public_question_bank')

        self.post_with_token(self.questionbankHelper.archive_question_bank_url,
                             {'question_bank_id': question_bank_id, 'context_institute_id': self.institute['id'], })
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'question_bank_id': question_bank_id, })

        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual(True, response_data['data']["question_bank"]["archived"], error_message)

    def test_question_banks_list_error(self):
        # error: invalid institute_id
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {
                                                                               'context_institute_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'archived_filter': 'include',
                                                                               'sort_by': 'created_at_asc', 'skip': 0,
                                                                               'take': 5, })
        self.assertEqual('error', response_data['status'], error_message)
        self.assertEqual('Forbidden', response_data['message'], error_message)

        # error: serializer
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {'context_institute_id': '',
                                                                            'archived_filter': 'include',
                                                                            'sort_by': 'created_at_asc', 'skip': 0, 'take': 5, })
        self.assertEqual('validation_error', response_data['status'], error_message)

        # error: serializer
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {
                                                                               'context_institute_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'archived_filter': 'include',
                                                                               'sort_by': 'created_at_asc', 'take': 5, })
        self.assertEqual('validation_error', response_data['status'], error_message)

        # error: serializer
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {
                                                                               'context_institute_id': '2d3e3a50-ccb9-43ae-b58a-dfbbc8cb7363',
                                                                               'archived_filter': 'include',
                                                                               'sort_by': 'created_at_asc', 'skip': 0, })
        self.assertEqual('validation_error', response_data['status'], error_message)

    def test_question_banks_list_success(self):
        for i in range(3):
            self.questionbankHelper.create_question_bank(self.institute['id'])
        self.questionbankHelper.create_question_bank(self.institute['id'], name='my_wikiazma')

        # creating a public question bank
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], public=True)

        # subscribing user2 to the public question bank created above
        (self.user_2, self.user_2_token) = self.authenticateHelper.new_user_with_email(email="owner_user@nisodynamic.com")

        self.institute_2 = Institute.objects.create(user=self.user_2, name='some')
        Access.objects.create(user=self.user_2, institute=self.institute_2, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_2.name)
        question_bank = QuestionBank.objects.get(id=question_bank_id)
        self.institute_2.subscribe_qb(question_bank.pk)

        # creating an archived private question bank
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_wikiazma2')
        self.questionbankHelper.archive_question_bank_helper(self.institute['id'], question_bank_id)

        # creating an archived public question bank
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_wikiazma3', public=True)
        self.questionbankHelper.archive_question_bank_helper(self.institute['id'], question_bank_id)

        # institute2, q not sent, archived_filter=include
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {'context_institute_id': self.institute_2.id,
                                                                            'archived_filter': 'include',
                                                                            'sort_by': 'created_at_asc',
                                                                            'skip': 0, 'take': 10, },
                                                                           test_token=self.user_2_token, application_json=True)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual(1, len(response_data['data']['question_banks']), error_message)

        # institute1, q not sent, archived_filter=include
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'archived_filter': 'include',
                                                                            'sort_by': 'created_at_asc', 'skip': 0,
                                                                            'take': 10, },
                                                                           application_json=True)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual(7, len(response_data['data']['question_banks']), error_message)

        # q sent, archived_filter=include
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'archived_filter': 'include',
                                                                            'sort_by': 'created_at_asc', 'skip': 0, 'take': 10,
                                                                            'q': 'wikiazma', }, application_json=True)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual(3, len(response_data['data']['question_banks']), error_message)

        # q sent, archived_filter=only
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'archived_filter': 'only',
                                                                            'sort_by': 'created_at_asc', 'skip': 0, 'take': 10,
                                                                            'q': 'wikiazma', },
                                                                           application_json=True)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual(2, len(response_data['data']['question_banks']), error_message)

        # non-existence q
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_list_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'archived_filter': 'include',
                                                                            'sort_by': 'created_at_asc', 'skip': 0, 'take': 10,
                                                                            'q': 'non-existence-name'}, application_json=True)
        self.assertEqual('ok', response_data['status'], error_message)
        self.assertEqual(0, len(response_data['data']['question_banks']), error_message)

    def test_payment_required_for_creating_question_banks(self):
        max_question_banks_per_institute = 2
        Environment.objects.update(default_max_question_banks_per_institute=max_question_banks_per_institute)

        for item in range(max_question_banks_per_institute):
            self.questionbankHelper.create_question_bank(self.institute['id'])
        request = {'context_institute_id': self.institute['id'], 'name': "valid_name"}
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.create_question_bank_url,
                                                                           request)
        self.assertEqual(402, status_code, error_message)
        self.assertEqual('Payment Required', response_data['message'], error_message)

    def test_tag_key_suggestion_successful(self):
        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank')

        # adding two questions to check for tags key-value suggestions
        tags = json.dumps({'subject': 'circles', 'subject2': 'square', 'field': 'math'})
        self.questionHelper.new_question(question_bank_id, tags=tags)

        tags = json.dumps({'subject': 'circular matter'})
        self.questionHelper.new_question(question_bank_id, tags=tags)

        # test finding two keys
        request = {'q': 'sub', 'question_bank_id': question_bank_id, 'context_institute_id': self.institute['id'], 'skip': 0,
                   'take': 10}
        self.questionbankHelper.check_key_suggestions(request, ['subject', 'subject2'])

        # test finding one key
        request = {'q': 'fie', 'question_bank_id': question_bank_id, 'context_institute_id': self.institute['id'], 'skip': 0,
                   'take': 10}
        self.questionbankHelper.check_key_suggestions(request, ['field'])

        # test finding no keys
        request = {'q': 'nonExistenceKey', 'question_bank_id': question_bank_id, 'context_institute_id': self.institute['id'],
                   'skip': 0, 'take': 10}
        self.questionbankHelper.check_key_suggestions(request, [])

        # test finding two values
        request = {'key': 'subject', 'q': 'cir', 'question_bank_id': question_bank_id,
                   'context_institute_id': self.institute['id'], 'skip': 0, 'take': 10}
        self.questionbankHelper.check_value_suggestions(request, ['circles', 'circular matter'])

        # test finding no values when the key exists
        request = {'key': 'subject', 'q': 'nonExistenceValue', 'question_bank_id': question_bank_id,
                   'context_institute_id': self.institute['id'], 'skip': 0, 'take': 10}
        self.questionbankHelper.check_value_suggestions(request, [])

        # test finding no values when the key does not exist
        request = {'key': 'nonExistenceKey', 'q': 'nonExistenceValue', 'question_bank_id': question_bank_id,
                   'context_institute_id': self.institute['id'], 'skip': 0, 'take': 10}
        self.questionbankHelper.check_value_suggestions(request, [])

    def test_tag_list_successful(self):
        if random.getrandbits(1) == 0:
            # creating another question bank with questions and tags should not affect our question bank
            self.questionbankHelper.create_a_question_bank_with_questions_and_tags(self.institute['id'], name=None)

        question_bank_id = self.questionbankHelper.create_question_bank(self.institute['id'], name='my_question_bank')

        # adding several tags for test
        tags = json.dumps({'subject': 'circles', 'subject2': 'square', 'field': 'math'})
        self.questionHelper.new_question(question_bank_id, tags=tags)

        # we have two 'subject2' and they should be retrieved in alphabetical order
        tags = json.dumps({'subject2': 'zoology'})
        self.questionHelper.new_question(question_bank_id, tags=tags)

        # create 'subject': 'circular matter' 3 times and 'subject2': 'zoology' 2 times
        tags = json.dumps({'subject': 'circular matter'})
        self.questionHelper.new_question(question_bank_id, tags=tags)
        self.questionHelper.new_question(question_bank_id, tags=tags)

        tags = json.dumps({'subject': 'circular matter', 'subject2': 'zoology'})
        self.questionHelper.new_question(question_bank_id, tags=tags)

        # creating and deleting some more tags
        tags = json.dumps({'subject': 'circular matter', 'subject2': 'zoology'})
        response_data, status_code, error_message = self.questionHelper.new_question(question_bank_id, tags=tags)
        self.questionHelper.archive_question_helper(question_bank_id, response_data['data']['question']['id'])

        if random.getrandbits(1) == 0:
            # creating another question bank with questions and tags should not affect our question bank
            self.questionbankHelper.create_a_question_bank_with_questions_and_tags(self.institute['id'],
                                                                                   name='full_question_bank2')

        # TODO I should test expected_filters
        # keys are alphabetically ordered
        # TODO should be alphabetically ordered
        # expected_suggestions = [
        #     {'key': 'field', 'order': 0, 'values': [{'value': 'math', 'stock': 1, 'children': [], 'order': 0}]},
        #     {'key': 'subject', 'order': 1, 'values': [
        #         {'value': 'circles', 'stock': 1, 'children': [], 'order': 0},
        #         {'value': 'circular matter', 'stock': 3, 'children': [], 'order': 0}
        #     ]},
        #     {'key': 'subject2', 'order': 2, 'values': [
        #         # values are alphabetically ordered
        #         {'value': 'square', 'stock': 1, 'children': [], 'order': 0},
        #         {'value': 'zoology', 'stock': 2, 'children': [], 'order': 0}
        #     ]}]

        # TODO are not alphabetically ordered. use the above expected_suggestions
        expected_suggestions = [{'key': 'subject', 'order': 0,
                                 'values': [{'value': 'circles', 'stock': 1, 'children': [], 'order': 0},
                                            {'value': 'circular matter', 'stock': 3, 'children': [], 'order': 1}]},
                                {'key': 'subject2', 'order': 1,
                                 'values': [{'value': 'square', 'stock': 1, 'children': [], 'order': 0},
                                            {'value': 'zoology', 'stock': 2, 'children': [], 'order': 1}]},
                                {'key': 'field', 'order': 2,
                                 'values': [{'value': 'math', 'stock': 1, 'children': [], 'order': 0}]}]

        # test tags in question_bank get
        request = {'question_bank_id': question_bank_id, 'context_institute_id': self.institute['id']}
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.get, request)
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertIn('tags', response_data['data']['question_bank'], error_message)
        self.assertIn('filters', response_data['data']['question_bank'], error_message)
        self.assertEqual(len(response_data['data']['question_bank']['tags']), len(expected_suggestions), error_message)
        for i in range(len(expected_suggestions)):
            self.assertEqual(response_data['data']['question_bank']['tags'][i], expected_suggestions[i], error_message)

        # test tags in question_bank tag_list
        request = {'question_bank_id': question_bank_id, 'context_institute_id': self.institute['id']}
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.tag_list, request)
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(len(response_data['data']['tags']), len(expected_suggestions), error_message)
        for i in range(len(expected_suggestions)):
            self.assertEqual(response_data['data']['tags'][i], expected_suggestions[i], error_message)

    def test_question_bank_market_place_picked(self):
        # creating a featured question bank
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="saleh@yahoo.com", password='dEdhbd3Ethdset')
        self.institute_2 = Institute.objects.create(user=user2, name='some')
        Access.objects.create(user=user2, institute=self.institute_2, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_2.name)
        self.post_with_token(self.questionbankHelper.create_question_bank_url,
                             {'context_institute_id': self.institute_2.id, 'name': 'featured_question_bank', 'public': True,
                              'price': 0},
                             test_token=user2_token)

        created_question_bank = QuestionBank.objects.all()[0]
        created_question_bank.featured = True
        created_question_bank.save()

        # The featured question_bank should appear in marketplace
        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="include",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(1, len(response_data['data']['question_banks']), error_message)
        self.assertEqual(False, response_data['data']['question_banks'][0]['picked'], error_message)

        # subscribing to the featured question_bank
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_pick_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'question_bank_id': created_question_bank.id})
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)

        # When we subscribe to a question_bank in marketplace, it will be removed from it in my next marketplace calls
        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="include",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(0, len(response_data['data']['question_banks']), error_message)

        # unsubscribe the featured question_bank
        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.unsubscribe_url,
                                                                           {'context_institute_id': self.institute['id'],
                                                                            'question_bank_id': created_question_bank.id})
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)

        # After unsubscribe, it should be back to the previous state
        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="include",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(1, len(response_data['data']['question_banks']), error_message)
        self.assertEqual(False, response_data['data']['question_banks'][0]['picked'], error_message)

    def test_questions_bank_market_place(self):
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="saleh@yahoo.com", password='dEdhbd3Ethdset')
        institute_2 = Institute.objects.create(user=user2, name='some')
        Access.objects.create(user=user2, institute=institute_2, roles=["__ROLE_OWNER__"], institute_name=institute_2.name)

        # create a private question bank that should not be present in marketplace
        self.questionbankHelper.create_question_bank(institute_2.id, name='my_question_bank_private', token=user2_token)

        num_free_questions_bank = random.randint(1, 4)
        for i in range(num_free_questions_bank):
            QuestionBank.objects.create(institute=institute_2, name='my_free_question_bank ' + str(i), accessibility='public',
                                        featured=True)

        num_non_free_questions_bank = random.randint(1, 4)
        for i in range(num_non_free_questions_bank):
            QuestionBank.objects.create(institute=institute_2, name='my_non_free_question_bank ' + str(i), accessibility='public',
                                        featured=True, price=10000)

        # free_filter="include"
        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="include",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(num_free_questions_bank + num_non_free_questions_bank, len(response_data['data']['question_banks']),
                         error_message)

        # free_filter="exclude"
        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="exclude",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])

        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(num_non_free_questions_bank, len(response_data['data']['question_banks']), error_message)

        # free_filter="only"
        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="only",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])

        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)
        self.assertEqual(num_free_questions_bank, len(response_data['data']['question_banks']), error_message)

    def test_questions_bank_market_place_error(self):
        self.questionbankHelper.create_question_bank(self.institute['id'], name=None, public=False)

        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10, free_filter="",
                                                                                                  context_institute_id=
                                                                                                  self.institute['id'])

        self.assertEqual(status_code, 400, error_message)
        self.assertEqual(response_data['message'], 'Some fields are not valid', error_message)
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="saleh@yahoo.com", password='dEdhbd3Ethdset')
        self.institute_2 = Institute.objects.create(user=user2, name='some')
        Access.objects.create(user=user2, institute=self.institute_2, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_2.name)
        self.questionbankHelper.create_question_bank(self.institute['id'], name=None, public=False)

        (response_data, status_code, error_message) = self.questionbankHelper.market_place_helper(skip=0, take=10,
                                                                                                  free_filter="only",
                                                                                                  context_institute_id=self.institute_2.id)

        self.assertEqual(status_code, 403, error_message)
        self.assertEqual(response_data['message'], 'Forbidden', error_message)

    def test_question_bank_pick_successful(self):
        (user2, user2_token) = self.authenticateHelper.new_user_with_email(email="saleh@yahoo.com", password='dEdhbd3Ethdset')
        self.institute_2 = Institute.objects.create(user=user2, name='some')
        Access.objects.create(user=user2, institute=self.institute_2, roles=["__ROLE_OWNER__"],
                              institute_name=self.institute_2.name)
        question_bank_id_public = self.questionbankHelper.create_question_bank(self.institute['id'],
                                                                               name='my_question_bank_public', public=True)

        (response_data, status_code, error_message) = self.post_with_token(self.questionbankHelper.question_bank_pick_url,
                                                                           {'context_institute_id': self.institute_2.id,
                                                                            'question_bank_id': question_bank_id_public},
                                                                           test_token=user2_token)
        self.assertEqual(status_code, 200, error_message)
        self.assertEqual(response_data['message'], 'Successful', error_message)

    def test_question_bank_pick_error(self):
        question_bank_id_public = self.questionbankHelper.create_question_bank(self.institute['id'],
                                                                               name='my_question_bank_public', public=True)
        (response_data, status_code, error_message) = self.questionbankHelper.question_bank_pick(
            context_institute_id=self.institute['id'], question_bank_id=question_bank_id_public)
        self.assertEqual(status_code, 200, error_message)

        question_bank_id_private = self.questionbankHelper.create_question_bank(self.institute['id'],
                                                                                name='my_question_bank_private')
        (response_data, status_code, error_message) = self.questionbankHelper.question_bank_pick(
            context_institute_id=self.institute['id'], question_bank_id=question_bank_id_private)
        self.assertEqual(status_code, 403, error_message)
        self.assertEqual(response_data['message'], 'Forbidden', error_message)

        (response_data, status_code, error_message) = self.questionbankHelper.question_bank_pick(
            context_institute_id=self.institute['id'], question_bank_id="93e275a3-aef5-4372-81ff-c2abeab995bc")
        self.assertEqual(status_code, 400, error_message)
        self.assertEqual(response_data['message'], 'BadRequest', error_message)
