import json

from question.models import Question, QUESTION_TYPE_MULTIPLE_CHOICE
from question_bank.models import QuestionBank


class QuestionTestHelper:

    def __init__(self, tester):
        self.tester = tester

    name_index = 0

    create_question_url = '/question/create'
    bulk_create_question_url = '/question/bulk_create'
    edit_question_url = '/question/edit'
    archive_question_url = '/question/delete'
    list_question_url = '/question/list'
    get_question_url = '/question/get'

    def new_name(self):
        self.name_index += 1
        return 'QuestionName' + str(self.name_index)

    def create_question_with_defaults(self, question_bank_id, keywords=None, question_text=None, format=None, question_type=None,
                                      input_rules=None, tags=None, token=None, solution=None, choices=None, correct_choices=None):

        if keywords is None:
            keywords = 'solve x^2-2x+1=0'

        if question_text is None:
            question_text = 'choose a correct answer for x in equation --x^2 - 2x + 1 = 0--'

        if solution is None:
            solution = 'x=1'

        if format is None:
            format = 'markdownV1'

        if question_type is None:
            question_type = 'multiple-choice'

        if tags is None:
            tags = json.dumps({'subject': 'math'})
        elif type(tags) is not str:
            tags = json.dumps(tags)

        if input_rules is None:
            if question_type == 'multiple-choice':
                # Reference #856245
                input_rules = {
                    "max_selectable_choices": 2
                }
            else:
                input_rules = {
                    "max_characters": 1000,
                    "attachment": True,
                }

        if type(input_rules) is not str:
            input_rules = json.dumps(input_rules)

        if choices is None and question_type == QUESTION_TYPE_MULTIPLE_CHOICE:
            choices = {
                12345678: "...",
                12345677: "...",
                12345676: "...",
                12345675: "...",
                12345674: "...",
            }

        if type(choices) is dict:
            choices = json.dumps(choices)

        if correct_choices is None and question_type == QUESTION_TYPE_MULTIPLE_CHOICE:
            # Comment id #68246256;
            correct_choices = [12345678]

        # if type(correct_choices) is not str:
        #     correct_choices = json.dumps(correct_choices)

        request = {'question_bank_id': question_bank_id, 'keywords': keywords, 'question_text': question_text,
                   'format': format, 'question_type': question_type, 'input_rules': input_rules, 'tags': tags,
                   'solution': solution}
        if choices:
            request['choices'] = choices
        if choices:
            request['correct_choices'] = correct_choices

        return self.tester.post_with_token(self.create_question_url, request, test_token=token)

    def new_question(self, question_bank_id, keywords=None, question_text=None, question_text_format=None, question_type=None,
                     input_rules=None, choices=None, correct_choices=None, tags=None, answer_sheet_text=None, status_200=True):
        (response_data, status_code, error_message) = self.create_question_with_defaults(question_bank_id, keywords=keywords,
                                                                                         question_text=question_text,
                                                                                         format=question_text_format,
                                                                                         question_type=question_type,
                                                                                         input_rules=input_rules, choices=choices,
                                                                                         correct_choices=correct_choices,
                                                                                         tags=tags,
                                                                                         solution=answer_sheet_text)
        if status_200:
            self.tester.assertEqual(200, status_code, error_message)
            self.tester.assertEqual(
                'Successful', response_data['message'], error_message)

        # question = Question.objects.get(name=name, question_bank_id=question_bank_id)
        return response_data, status_code, error_message

    def archive_question_helper(self, question_bank_id, question_id):
        question_bank = QuestionBank.objects.get(id=question_bank_id)

        previous_questions_count = question_bank.questions_count

        (response_data, status_code, error_message) = self.tester.post_with_token(self.archive_question_url,
                                                                                  {'question_id': question_id})
        self.tester.assertEqual(200, status_code, error_message)
        self.tester.assertEqual('ok', response_data['status'], error_message)
        question_bank = QuestionBank.objects.get(id=question_bank_id)
        question = Question.objects.get(id=question_id)

        self.tester.assertEqual(
            previous_questions_count - 1, question_bank.questions_count)
        self.tester.assertEqual(True, question.archived)

    def check_question_bank_number_of_questions(self, question_bank_id, num_questions, context_institute_id):
        request = {'question_bank_id': question_bank_id, 'context_institute_id': context_institute_id, 'skip': 0,
                   'take': 10, 'archived_filter': 'include', 'sort_by': 'keywords_asc', 'auto_correctable_filter': 'include'}
        (response_data, status_code, error_message) = self.tester.post_with_token(
            self.list_question_url, request)
        self.tester.assertEqual(200, status_code, error_message)
        self.tester.assertEqual(
            response_data['message'], 'Successful', error_message)
        self.tester.assertEqual(
            len(response_data['data']['questions']), num_questions, error_message)

    def wrong_answer_rule_checker(self, question_bank_id, input_rules, choices, correct_choices, expected_error_field_name,
                                  expected_error):
        (response_data, status_code, error_message) = self.create_question_with_defaults(
            question_bank_id, input_rules=input_rules, choices=choices, correct_choices=correct_choices)

        self.tester.assertEqual(400, status_code, error_message)
        self.tester.assertEqual(
            'validation_error', response_data['status'], error_message)
        self.tester.assertEqual(
            'Some fields are not valid', response_data['message'], error_message)
        self.tester.assertIn(expected_error_field_name,
                             response_data['fields'], error_message)

        self.tester.assertEqual(
            expected_error, response_data['fields'][expected_error_field_name], error_message)

    def tag_filter_helper(self, question_bank_id, institute_id, tag_filters, expected_question_names):
        request = {'question_bank_id': question_bank_id, 'context_institute_id': institute_id, 'skip': 0, 'take': 10,
                   'archived_filter': 'include', 'sort_by': 'keywords_asc', 'auto_correctable_filter': 'include',
                   'tag_filters': json.dumps(tag_filters)}
        (response_data, status_code, error_message) = self.tester.post_with_token(self.list_question_url, request)
        self.tester.assertEqual(200, status_code, error_message)
        self.tester.assertEqual(len(expected_question_names), len(response_data['data']['questions']), error_message)
        for index, expected_question_name in enumerate(expected_question_names):
            self.tester.assertEqual(expected_question_name, response_data['data']['questions'][index]['keywords'], error_message)

    def create_questions_with_real_tags(self, question_bank_id):
        self.new_question(question_bank_id,
                          keywords='q1_1_1',
                          tags=json.dumps({'فصل': '1', 'درس': '1', 'درجه سختی': 'آسان', 'مبحث': 'گرامر'}))
        self.new_question(question_bank_id,
                          keywords='q1_2_1',
                          tags=json.dumps({'فصل': '1', 'درس': '2', 'درجه سختی': 'آسان', 'مبحث': 'گرامر'}))
        self.new_question(question_bank_id,
                          keywords='q1_2_2',
                          tags=json.dumps({'فصل': '1', 'درس': '2', 'درجه سختی': 'سخت', 'مبحث': 'کلمه'}))
        self.new_question(question_bank_id,
                          keywords='q1_3_1',
                          tags=json.dumps({'فصل': '1', 'درس': '3', 'درجه سختی': 'آسان', 'مبحث': 'کلمه'}))
        self.new_question(question_bank_id,
                          keywords='q2_1_1',
                          tags=json.dumps({'فصل': '2', 'درس': '1', 'درجه سختی': 'آسان', 'مبحث': 'گرامر'}))
        self.new_question(question_bank_id,
                          keywords='q2_2_1',
                          tags=json.dumps({'فصل': '2', 'درس': '2', 'درجه سختی': 'آسان', 'مبحث': 'گرامر'}))
        self.new_question(question_bank_id,
                          keywords='q2_2_2',
                          tags=json.dumps({'فصل': '2', 'درس': '2', 'درجه سختی': 'سخت', 'مبحث': 'کلمه'}))
        self.new_question(question_bank_id,
                          keywords='q2_3_1',
                          tags=json.dumps({'فصل': '2', 'درس': '4', 'درجه سختی': 'آسان', 'مبحث': 'کلمه'}))
