# import numbers
#
# from rest_framework import serializers
#
# from exam.models import ALLOWED_REPORT_CARD_STRATEGIES, ALLOWED_ENTRANCE_TYPES
# from exam.utils import ALLOWED_ACCESS_TYPES
# from question.models import QUESTION_TYPE_DATABASE_CHOICES, QUESTION_TYPE_SERIALIZER_CHOICES
# from exam.models import ALLOWED_ANSWER_TEXT_FORMAT
# from utils.validators import dic_validetor, uuid_checker
#
# from exam import conf
#
# def exam_rule_validator(data):
#     # check if rules is a dictionary
#     if type(data) is not dict:
#         raise serializers.ValidationError({'rules': 'rules should be a json object'})
#
#     # check for required and optional fields
#     groups ={
#         'key':'groups',
#         'type':list,
#         'validator': lambda groups: len(groups) > 0,
#         'validator_error_message':'At least one group should be added'
#     }
#     required_items = [groups]
#     # check_for_required_and_optional_fields(data, required_items, [], 'rules', 'rules', parent_is_array=False)
#     dic_validetor(data,required_items=required_items,error_key='rules',many=False,container_name='rules', raise_error_for_unexpected_key=True)
#
#     # if type(data['groups']) is not list:
#     #     raise serializers.ValidationError({'rules': 'groups should be a list'})
#
#     # if len(data['groups']) == 0:
#     #     raise serializers.ValidationError({'rules': 'At least one group should be added'})
#
#     groups_ids = []
#     groups_names = []
#     for group in data['groups']:
#         if len(data['groups']) == 1:
#             group_validator(group, many=False)
#         else:
#             group_validator(group, many=True)
#
#         if group['id'] in groups_ids:
#             raise serializers.ValidationError({'rules': f'Duplicate group id "{group["id"]}"'})
#
#         if group['name'] in groups_names:
#             raise serializers.ValidationError({'rules': f'Duplicate group name "{group["name"]}"'})
#
#         groups_names.append(group['name'])
#         groups_ids.append(group['id'])
#
#     # duplicate question_id is permitted here
#
#
# QUERY_QUESTION_BY_ID = 'QueryQuestionById'
# QUERY_QUESTION_LIST_BY_FILTERING = 'QueryQuestionListByFiltering'
# ALLOWED_QUERY_QUESTION_TYPES = [QUERY_QUESTION_BY_ID, QUERY_QUESTION_LIST_BY_FILTERING]
#
#
# def group_validator(data, many):
#     # check if rules is a dictionary
#     if type(data) is not dict:
#         raise serializers.ValidationError({'rules': 'Each group should be a json object'})
#
#     # check for required and optional fields
#     # according to my talk with Mr. Emami, we don't have nested groups. Also we don't have a duration for groups
#     id ={
#         'key':'id',
#         'type':int,
#         'validator': lambda id: 10000000  <= id <= 99999999 ,
#         'validator_error_message':'id should be integer and should be between 10000000, 99999999'
#     }
#
#
#
#     name ={
#         'key':'name',
#         'type':str,
#         'validator': lambda name:   0< len(name)<=1000,
#         'validator_error_message':  'In each group, name should be at most 1000 characters'
#     }
#     questions ={
#         'key':'questions',
#         'type':list,
#         'validator': lambda questions:  len(questions)>0,
#         'validator_error_message':  'At least one question should be added in each group'
#     }
#     required_items = [id,name,questions]
#     # check_for_required_and_optional_fields(data, required_items, [], 'groups', 'rules', parent_is_array=True)
#     dic_validetor(data,required_items=required_items,error_key='rules',many=True,container_name='groups', raise_error_for_unexpected_key=True)
#
#     # if type(data['id']) is not int or not 10000000 < data['id'] < 99999999:
#     #     raise serializers.ValidationError({'rules': 'id should be integer and should be between 10000000, 99999999'})
#
#
#
#     # if type(data['questions']) is not list:
#     #     raise serializers.ValidationError({'rules': 'In each group, questions should be a list'})
#
#
#     for question in data['questions']:
#         if type(question) is not dict:
#             raise serializers.ValidationError({'rules': 'each "question" should be a json object'})
#
#         if 'type' not in question:
#             raise serializers.ValidationError({'rules': 'Each question must have a "type" field'})
#
#         if type(question['type']) is not str:
#             raise serializers.ValidationError({'rules': 'type should be string in each question'})
#
#         if question['type'] == QUERY_QUESTION_BY_ID:
#             query_question_by_id_object_validator(question)
#         elif question['type'] == QUERY_QUESTION_LIST_BY_FILTERING:
#             query_question_list_by_filtering_object_validator(question)
#         else:
#             raise serializers.ValidationError(
#                 {'rules': f'in each question, type should be one of {", ".join(ALLOWED_QUERY_QUESTION_TYPES)}'})
#
#
# def query_question_by_id_object_validator(data):
#     # we already checked if the question is dict
#     # check for required fields
#     # required_items = {'type':str, 'priority':int, 'positive_score': float, 'negative_score':float, 'duration':float, 'question_id':str, 'access_type':str}
#     priority ={
#         'key':'priority',
#         'type':int,
#     }
#
#     type = {
#         'key':'type',
#         'type':str
#     }
#     positive_score = {
#         'key':'positive_score',
#         'type':float
#     }
#
#     negative_score = {
#         'key':'negative_score',
#         'type':float
#     }
#
#     duration = {
#         'key':'duration',
#         'type':float,
#         'validator': lambda duration: duration  > 5.0,
#         'validator_error_message':'in each question, duration should be a float number and greater than 5'
#     }
#
#     question_id = {
#         'key':'question_id',
#         'type':str,
#         'validator': lambda question_id :uuid_checker(question_id) ,
#         'validator_error_message':f'"{data["question_id"]}" is not a valid UUID.'
#     }
#
#     # access_type = {
#     #     'key':'access_type',
#     #     'type':str,
#     #     'validator': lambda access_type: access_type in ALLOWED_ACCESS_TYPES ,
#     #     'validator_error_message':f'access_type should be one of {", ".join(ALLOWED_ACCESS_TYPES)}'
#     # }
#
#
#     required_items = [priority,type,positive_score,negative_score,duration,question_id]
#     # check_for_required_and_optional_fields(data, required_items, [], 'questions', 'rules', parent_is_array=True)
#     dic_validetor(data,required_items=required_items,error_key='rules',many=True,container_name='questions', raise_error_for_unexpected_key=True)
#
#     # if type(data['priority']) is not int:
#     #     raise serializers.ValidationError({'rules': 'in each question, priority should be integer'})
#
#     # if not isinstance(data['positive_score'], numbers.Number):
#     #     raise serializers.ValidationError({'rules': 'in each question, positive_score should be a float number'})
#
#     # if not isinstance(data['negative_score'], numbers.Number):
#     #     raise serializers.ValidationError({'rules': 'in each question, negative_score should be a float number'})
#
#     # if not isinstance(data['duration'], numbers.Number) or data['duration'] < 5.0:
#     #     raise serializers.ValidationError(
#     #         {'rules': 'in each question, duration should be a float number and greater than 5'})
#
#     # if type(data['question_id']) is not str:
#     #     raise serializers.ValidationError({'rules': 'in each question, question_id should be string(UUID)'})
#
#     # if not uuid_checker(data['question_id']):
#     #     raise serializers.ValidationError({'rules': f'"{data["question_id"]}" is not a valid UUID.'})
#
#     # if type(data['access_type']) is not str or data['access_type'] not in ALLOWED_ACCESS_TYPES:
#     #     raise serializers.ValidationError({'rules': f'access_type should be one of {", ".join(ALLOWED_ACCESS_TYPES)}'})
#
#
# def query_question_list_by_filtering_object_validator(data):
#     # we already checked if the question is dict
#     # check for required fields
#     type = {
#         'key':'type',
#         'type':str
#     }
#
#     priority = {
#         'key':'priority',
#         'type':int
#     }
#
#     question_bank_id = {
#         'key':'question_bank_id',
#         'type':str,
#         'validator': lambda question_bank_id: uuid_checker(question_bank_id),
#         'validator_error_message':f'"{data["question_bank_id"]}" is not a valid UUID.'
#     }
#
#     # access_type = {
#     #     'key':'access_type',
#     #     'type':str,
#     #     'validator': lambda access_type: access_type in ALLOWED_ACCESS_TYPES ,
#     #     'validator_error_message':f'access_type should be one of {", ".join(ALLOWED_ACCESS_TYPES)}'
#     # }
#
#     tag_filters = {
#         'key':'tag_filters',
#         'type':list
#     }
#
#
#     count = {
#         'key':'count',
#         'type':int
#     }
#
#     positive_score_per_question = {
#         'key':'positive_score_per_question',
#         'type':float
#     }
#
#     negative_score_per_question = {
#         'key':'negative_score_per_question',
#         'type':float
#     }
#
#
#     duration_per_question = {
#         'key':'duration_per_question',
#         'type':float,
#         'validator': lambda duration_per_question: duration_per_question  > 5.0,
#         'validator_error_message':'in each question, duration_per_question should be a float number and greater than 5'
#     }
#
#     type_filter = {
#         'key':'type_filter',
#         'type':str,
#         'validator': lambda type_filter: type_filter in QUESTION_TYPE_SERIALIZER_CHOICES,
#         'validator_error_message':f'In each question, type_filter should be one of {", ".join(QUESTION_TYPE_SERIALIZER_CHOICES)}'
#     }
#
#     required_items = [type,priority,question_bank_id,tag_filters,count,positive_score_per_question,negative_score_per_question,duration_per_question]
#     # required_items = {'type': str, 'priority':int, 'question_bank_id':str, 'access_type':str, 'tag_filters':list, 'count':int,
#     #                   'positive_score_per_question':float, 'negative_score_per_question':float, 'duration_per_question':float}
#     optional_items = [type_filter]
#     # check_for_required_and_optional_fields(data, required_items, [], 'questions', 'rules', parent_is_array=True)
#     dic_validetor(data,required_items=required_items, optional_items=optional_items,error_key='rules',many=True,container_name='questions', raise_error_for_unexpected_key=True)
#
#
#     # if type(data['priority']) is not int:
#     #     raise serializers.ValidationError({'rules': 'in each question, priority should be integer'})
#
#     # if type(data['question_bank_id']) is not str:
#     #     raise serializers.ValidationError({'rules': 'in each question, question_bank_id should be string(UUID)'})
#
#     # if not uuid_checker(data['question_bank_id']):
#     #     raise serializers.ValidationError({'rules': f'"{data["question_bank_id"]}" is not a valid UUID.'})
#
#     # if type(data['access_type']) is not str or data['access_type'] not in ALLOWED_ACCESS_TYPES:
#     #     raise serializers.ValidationError({'rules': f'access_type should be one of {", ".join(ALLOWED_ACCESS_TYPES)}'})
#
#     # if not isinstance(data['duration_per_question'], numbers.Number) or data['duration_per_question'] < 5.0:
#     #     raise serializers.ValidationError(
#     #         {'rules': 'in each question, duration_per_question should be a float number and greater than 5'})
#
#     # if not isinstance(data['positive_score_per_question'], numbers.Number):
#     #     raise serializers.ValidationError({'rules': 'in each question, positive_score_per_question should be a float number'})
#
#     # if not isinstance(data['negative_score_per_question'], numbers.Number):
#     #     raise serializers.ValidationError({'rules': 'in each question, negative_score_per_question should be a float number'})
#
#     # if type(data['tag_filters']) is not list:
#     #     raise serializers.ValidationError({'rules': 'In each question, tag_filters should be a list'})
#
#     # if 'type_filter' in data and data['type_filter'] not in  QUESTION_TYPE_CHOICES:
#     #     raise serializers.ValidationError(
#     #         {'rules': f'In each question, type_filter should be one of {", ".join(QUESTION_TYPE_CHOICES)}'})
#
#     for tag_filter in data['tag_filters']:
#         tag_filter_validator(tag_filter)
#
#
# def tag_filter_validator(tag_filter):
#     if type(tag_filter) is not dict:
#         raise serializers.ValidationError({'rules': 'each tag_filter should be a json object'})
#     key = {
#         'key':'key',
#         'type':str
#     }
#     value = {
#         'key':'value',
#         'type':str
#     }
#     required_items = [key,value]
#     # check_for_required_and_optional_fields(tag_filter, required_items, [], 'tag_filters', 'rules', parent_is_array=True)
#     dic_validetor(data=tag_filter,required_items=required_items,error_key='rules',many=True,container_name='tag_filters', raise_error_for_unexpected_key=True)
#
#     # if type(tag_filter['key']) is not str:
#     #     raise serializers.ValidationError({'rules': 'in each tag_filter, key should be string'})
#
#     # if type(tag_filter['value']) is not str:
#     #     raise serializers.ValidationError({'rules': 'in each tag_filter, value should be string'})
#
#
#
# # def answer_text_format_validator(input):
# #     if input not in ALLOWED_ANSWER_TEXT_FORMAT:
# #         raise serializers.ValidationError(
# #             f'answer_text_format should be one of {", ".join(ALLOWED_ANSWER_TEXT_FORMAT)}')
# #     return input
#
# def user_inputs_validator(data):
#     # check if user_inputs is a dictionary
#     if type(data) is not list:
#         raise serializers.ValidationError({'user_inputs': 'user_inputs should be a list'})
#
#     if len(data) == 0:
#         raise serializers.ValidationError({'user_inputs': 'At least one user_input is required'})
#
#     group_index = {
#         'key':'group_index',
#         'type':int,
#     }
#     question_index = {
#         'key':'question_index',
#         'type':int
#     }
#
#     answer_text = {
#         'key':'answer_text',
#         'type':str
#     }
#
#     answer_text_format = {
#         'key':'answer_text_format',
#         'type':str,
#         'validator': lambda format: format in ALLOWED_ANSWER_TEXT_FORMAT,
#         'validator_error_message':f'answer_text_format should be one of {", ".join(ALLOWED_ANSWER_TEXT_FORMAT)}'
#     }
#
#     answer_indexes = {
#         'key':'answer_indexes',
#         'type':list
#     }
#     # check for required and optional fields
#     required_items = [group_index, question_index]
#     optional_items = [answer_text,answer_text_format,answer_indexes]
#
#     for user_input in data:
#         # check_for_required_and_optional_fields(user_input, required_items, optional_items, 'user_inputs', 'rules', parent_is_array=True)
#         dic_validetor(data=user_input,required_items=required_items,optional_items=optional_items,error_key='rules',many=True,container_name='user_inputs', raise_error_for_unexpected_key=True)
#         # validations on answer_indexes, ... are don in views because we need more data for validating them
#         # if "answer_text_format" in user_input :
#         #     answer_text_format_validator(input = user_input['answer_text_format'])
#     # check for duplicate question_index in each group
#     user_input_question_priorities = {}
#     for user_input in data:
#         if user_input['group_index'] not in user_input_question_priorities:
#             user_input_question_priorities[user_input['group_index']] = []
#
#         if user_input['question_index'] in user_input_question_priorities[user_input['group_index']]:
#             raise serializers.ValidationError({
#                 'user_inputs': f'Duplicate question_index="{user_input["question_index"]}" in group_index={user_input["group_index"]}'})
#         user_input_question_priorities[user_input['group_index']].append(user_input['question_index'])
#
#
# def entrance_type_validator(entrance_type):
#     if entrance_type not in ALLOWED_ENTRANCE_TYPES:
#         raise serializers.ValidationError(
#             {'entrance_type': f'entrance_type should be one of {", ".join(ALLOWED_ENTRANCE_TYPES)}'})
#     return entrance_type
#
#
# def report_card_strategy_validator(report_card_strategy):
#     if report_card_strategy not in ALLOWED_REPORT_CARD_STRATEGIES:
#         raise serializers.ValidationError(
#             {'report_card_strategy': f'report_card_strategy should be one of {", ".join(ALLOWED_REPORT_CARD_STRATEGIES)}'})
#     return report_card_strategy
#
#
# def exam_sort_by_validator(sort_by):
#     from exam.views import list_exam_sort_by_switcher
#     allowed_sort_by_items = list_exam_sort_by_switcher.keys()
#     if sort_by not in allowed_sort_by_items:
#         raise serializers.ValidationError({'sort_by': f'sort_by should be one of {", ".join(allowed_sort_by_items)}'})
#     return sort_by
#
# def answer_file_validator(file):
#     if file.size > (1024 * 1024 * conf.maximum_file_size_MB):
#         raise serializers.ValidationError(f'The maximum file size is {conf.maximum_file_size_MB} MB')
#     return file