from rest_framework import serializers
from utils.validators import dic_validetor
from . import conf
from .models import QUESTION_TYPE_SERIALIZER_CHOICES, QUESTION_TYPE_DESCRIPTIVE, QUESTION_TYPE_MULTIPLE_CHOICE, \
    QUESTION_FORMAT_SERIALIZER_CHOICES
from rest_framework import serializers

from utils.validators import dic_validetor
from . import conf
from .models import QUESTION_TYPE_SERIALIZER_CHOICES, QUESTION_TYPE_DESCRIPTIVE, QUESTION_TYPE_MULTIPLE_CHOICE, \
    QUESTION_FORMAT_SERIALIZER_CHOICES


def question_format_validator(question_text_format):
    if question_text_format not in QUESTION_FORMAT_SERIALIZER_CHOICES:
        raise serializers.ValidationError(
            f'question_text_format should be one of {", ".join(QUESTION_FORMAT_SERIALIZER_CHOICES)}')
    return question_text_format


def question_type_validator(question_type):
    if question_type not in QUESTION_TYPE_SERIALIZER_CHOICES:
        raise serializers.ValidationError(
            f'question_type should be one of {", ".join(QUESTION_TYPE_SERIALIZER_CHOICES)}')
    return question_type


def tags_validator(tags):
    if type(tags) is not dict:
        raise serializers.ValidationError('tags should be a dictionary')
    if len(tags) > conf.maximum_tags_items:
        raise serializers.ValidationError(
            f'tags should be an object with at most {conf.maximum_tags_items} items')
    for tag in tags:
        if type(tag) is not str or type(tags[tag]) is not str or len(tag) > 100 or len(tags[tag]) > 100:
            raise serializers.ValidationError(
                'All keys and values must be strings with a maximum of 100 characters.')


allowed_answer_text_formats = ['markdownV1', 'htmlV1', 'jsonV1']


def questions_sort_by_validator(sort_by):
    allowed_questions_sort_by_items = [
        'keywords_asc', 'keywords_desc', 'created_at_asc', 'created_at_desc']
    if sort_by not in allowed_questions_sort_by_items:
        raise serializers.ValidationError(
            f'sort_by should be one of {", ".join(allowed_questions_sort_by_items)}')
    return sort_by


def input_rules_validator(input_rules, choices, question_type):
    if type(input_rules) != dict:
        raise serializers.ValidationError({'input_rules': 'input_rules should be a dictionary'})

    if question_type == QUESTION_TYPE_DESCRIPTIVE:

        max_characters = {
            'key': 'max_characters',
            'type': int,
            'validator': lambda value: 1 <= value <= 100000,

        }

        attachment = {
            'key': 'attachment',
            'type': bool,
        }

        dic_validetor(data=input_rules, required_items=[max_characters, attachment],
                      error_key='input_rules', many=False, container_name='input_rules', raise_error_for_unexpected_key=True)

    # check answer_rules validation if question_type is multiple-choice
    elif question_type == QUESTION_TYPE_MULTIPLE_CHOICE:

        max_selectable_choices = {
            'key': 'max_selectable_choices',
            'type': int,
            'validator': lambda max_selectable_choices: 1 <= max_selectable_choices <= len(choices),
            'validator_error_message': 'max_selectable_choices should be an integer between 1 and number of choices'
        }

        answer_rules_required_items = [max_selectable_choices]

        dic_validetor(data=input_rules, required_items=answer_rules_required_items,
                      error_key='input_rules', many=False, container_name='input_rules', raise_error_for_unexpected_key=True)

    else:
        raise serializers.ValidationError({'input_rules': 'bad state'})


def choices_validator(choices, correct_choices):
    if type(choices) != dict or not (2 <= len(choices.items()) <= 10):
        raise serializers.ValidationError(
            {'choices': 'choices should be a dict of at least 2 and at most 10 children'})

    for choice_id, choice_value in choices.items():

        if type(choice_id) != str or len(choice_id) > 10:
            raise serializers.ValidationError(
                {'choices': f'Invalid choice id {choice_id}'})
        elif type(choice_value) != str:
            raise serializers.ValidationError(
                {'choices': f'Invalid choice value for choice with id={choice_id}'})

    # correct_choice
    for correct_choice in correct_choices:
        if type(correct_choice) != str or correct_choice not in choices:
            raise serializers.ValidationError(
                {'correct_choices': f'Invalid correct choice id ({correct_choice})'})


def questions_sort_by_validator(sort_by):
    allowed_questions_sort_by_items = [
        'keywords_asc', 'keywords_desc', 'created_at_asc', 'created_at_desc', 'random']
    if sort_by not in allowed_questions_sort_by_items:
        raise serializers.ValidationError(
            f'sort_by should be one of {", ".join(allowed_questions_sort_by_items)}')
    return sort_by


def meta_validator(meta):
    if type(meta) is not dict:
        raise serializers.ValidationError('meta should be a dictionary')
