from django.core.validators import MinValueValidator, MaxValueValidator
from rest_framework import serializers

from authenticate import validators as authenticate_validators, serializers as authenticate_serializers
from authenticate.models import User
from collaborators import validators as collaborators_validator
from institute import conf, validators as institute_validators
from institute.models import Institute, InstituteStudent
from utils import validators as main_validators


################################################################################
######################### APIs Serializers #####################################
################################################################################


class CreateInstituteInputSerializer(serializers.Serializer):
    """
    This serializer class takes name & description from user and passed it to
    InstituteCreateAPIView to do some works on it.
    note that description is optional
    """
    name = serializers.CharField()
    description = serializers.CharField(required=False)
    logo = serializers.ImageField(required=False)
    poster = serializers.ImageField(required=False)
    info = serializers.JSONField(required=False)

    def validate_logo(self, value):
        main_validators.image_validetor(image=value, image_size_as_MB=conf.maximum_size_institute_logo_MG,
                                        format=conf.allowed_formats_for_institute_logo,
                                        max_side=conf.maximum_side_size_for_institute_logo)
        return value

    def validate_poster(self, value):
        main_validators.image_validetor(image=value, image_size_as_MB=conf.maximum_size_institute_poster_MG,
                                        format=conf.allowed_formats_for_institute_poster,
                                        max_side=conf.maximum_side_size_for_institute_poster)
        return value

    def validate_name(self, value):
        main_validators.name_validator(
            name=value, min_length=3, max_length=100)
        return value


class EditInstituteInputSerializer(serializers.Serializer):
    """
    This serializer class takes name, description & institute_id from user and passed it to
    InstituteEditAPIView to do some works on it.
    note that description is optional
    """
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])
    name = serializers.CharField()
    description = serializers.CharField(required=False, allow_blank=True)
    info = serializers.JSONField(required=False)
    logo = serializers.ImageField(required=False)
    poster = serializers.ImageField(required=False)
    delete_logo = serializers.BooleanField(default=False)
    delete_poster = serializers.BooleanField(default=False)

    def validate_logo(self, value):
        main_validators.image_validetor(image=value, image_size_as_MB=conf.maximum_size_institute_logo_MG,
                                        format=conf.allowed_formats_for_institute_logo,
                                        max_side=conf.maximum_side_size_for_institute_logo)
        return value

    def validate_poster(self, value):
        main_validators.image_validetor(image=value, image_size_as_MB=conf.maximum_size_institute_poster_MG,
                                        format=conf.allowed_formats_for_institute_poster,
                                        max_side=conf.maximum_side_size_for_institute_poster)
        return value

    def validate_name(self, value):
        main_validators.name_validator(
            name=value, min_length=3, max_length=100)
        return value


class DeleteInstituteInputSerializer(serializers.Serializer):
    """
    This serializer class takes institute_id from user and passed it to
    InstituteDeleteAPIView to do some works on it.
    """
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])


class AllInstitutesInputSerializer(serializers.Serializer):
    """
    This serializer class takes skip, take, sort_by & search_words from user and passed it to
    AllInstitutesAPIView to do some works on it.
    """
    search_words = serializers.CharField(required=False)
    skip = serializers.IntegerField(validators=[MinValueValidator(0)])
    take = serializers.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(100)])
    sort_by = serializers.CharField(
        validators=[institute_validators.access_sort_by_validator])


# TODO skip
# class OwnedInstitutesInputSerializer(serializers.Serializer):
#     """
#     This serializer class takes skip, take, sort_by & search_words from user and passed it to
#     OwnedInstitutesAPIView to do some works on it.
#     """
#     search_words = serializers.CharField(required=False)
#     skip = serializers.IntegerField(validators=[MinValueValidator(0)])
#     take = serializers.IntegerField(
#         validators=[MinValueValidator(1), MaxValueValidator(100)])
#     sort_by = serializers.CharField(
#         validators=[institute_validators.institute_sort_by_validator])


class IntersectionInstitutesInputSerializer(serializers.Serializer):
    """
    This serializer class takes skip, take, sort_by & email from user and passed it to
    IntersectionInstitutesAPIView to do some works on it.
    """
    email = serializers.CharField(max_length=254, validators=[
        authenticate_validators.email_validator])
    skip = serializers.IntegerField(validators=[MinValueValidator(0)])
    take = serializers.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(100)])
    sort_by = serializers.CharField(
        validators=[institute_validators.access_sort_by_validator])


# TODO : skip
# class TransferOwnerShipStateInputSerializer(serializers.Serializer):
#     """
#     This serializer class takes a institute_id from user and passed it to
#     TransferOwnerShipStateAPIView to do some works on it.
#     """
#     institute_id = serializers.CharField(
#         validators=[main_validators.uuid_validator])

# TODO : skip
# class TransferEmailCheckSerializer(serializers.Serializer):
#     """
#     This serializer class takes new_owner_email & institute_id from user and passed it to
#     TransferEmailCheckAPIView to do some works on it.
#     """
#     institute_id = serializers.CharField(
#         validators=[main_validators.uuid_validator])
#     new_owner_email = serializers.CharField(
#         max_length=254, validators=[authenticate_validators.email_validator])


class GetInstituteInputSerializer(serializers.Serializer):
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])


class InstituteAccessGetSerializer(serializers.Serializer):
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])


# TODO skip
# class MyAccessInputSerializer(serializers.Serializer):
#     token = serializers.CharField(max_length=460)
#     institute_id = serializers.CharField(validators=[main_validators.uuid_validator])


class GenerateAPIKeyInputSerializer(serializers.Serializer):
    token = serializers.CharField(max_length=460)
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])
    roles = serializers.JSONField(
        validators=[collaborators_validator.roles_validator])
    expire_at = serializers.DateTimeField()


class APIKeysListInputSerializer(serializers.Serializer):
    token = serializers.CharField(max_length=460)
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])


class DeleteAPIKeyInputSerializer(serializers.Serializer):
    token = serializers.CharField(max_length=460)
    api_key_id = serializers.CharField(
        validators=[main_validators.uuid_validator])


class GetTokenInputSerializer(serializers.Serializer):
    api_key = serializers.CharField(max_length=460)


################################################################################
######################### Models Serializers ###################################
################################################################################


class InstituteSerializerForExamAndInstituteAndQuestionBank(serializers.ModelSerializer):
    """
    This serializer class takes one or more Institute records and serializes them to json with desired fields.
    """
    owner = serializers.SerializerMethodField(method_name='owner_info')

    def owner_info(self, obj):
        return authenticate_serializers.UserSerializerForAuthenticateAndCollaboratorsAndInstitute(obj.user).data

    class Meta:
        model = Institute
        fields = ['id', 'name', 'description', 'logo', 'logo_thumbnail', 'poster', 'poster_thumbnail', 'info',
                  'on_exam_finished_redirect_url', 'sandbox', 'created_at', 'modified_at', 'owner']


# TODO skip
# class NewOwnerSerializer(serializers.ModelSerializer):
#     """
#     This serializer class takes one or more User records and serializes them to json with desired fields.
#     """

#     class Meta:
#         model = User
#         fields = ['first_name', 'last_name', 'email', 'image_thumbnail']

class UserSerializerForExam(serializers.ModelSerializer):
    """
    This serializer class takes one or more User records and serializes them to json with desired fields.
    """

    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'image_thumbnail']


# TODO : skip
# class TransferOwnershipHistorySerializer(serializers.ModelSerializer):
#     """
#     This serializer class takes one or more TransferOwnershipHistory records and serializes them to json with desired fields.
#     """
#     new_owner = serializers.SerializerMethodField()
#     new_owner_accept = serializers.SerializerMethodField()
#     old_owner_accept = serializers.SerializerMethodField()

#     def get_new_owner(self, obj):
#         return NewOwnerSerializer(obj.new_owner).data

#     def get_new_owner_accept(self, obj):
#         if obj.new_owner_accept_at:
#             return True
#         return False

#     def get_old_owner_accept(self, obj):
#         if obj.old_owner_accept_at:
#             return True
#         return False

# class Meta:
#     model = TransferOwnershipHistory
#     fields = ['id', 'new_owner', 'new_owner_accept', 'old_owner_accept']


class SetInstituteStudentInputValidator(serializers.Serializer):
    referer_institute_student_identity = serializers.CharField(max_length=100)
    first_name = serializers.CharField(
        max_length=46, required=False, allow_blank=True, allow_null=True)
    last_name = serializers.CharField(
        max_length=46, required=False, allow_blank=True, allow_null=True)
    email = serializers.CharField(
        max_length=254, required=False, allow_blank=True, allow_null=True)
    phone = serializers.CharField(
        max_length=20, required=False, allow_blank=True, allow_null=True)
    info = serializers.JSONField(required=False)


class GetInstituteStudentInputValidator(serializers.Serializer):
    wikiazma_institute_student_id = serializers.CharField(required=False)
    referer_institute_student_identity = serializers.CharField(required=False)

    def validate(self, data):
        """
        One out of many fields should be present.
        """
        fields = ['wikiazma_institute_student_id',
                  'referer_institute_student_identity']
        one_field_found = False
        for field in fields:
            if field in data:
                if one_field_found:
                    raise serializers.ValidationError(
                        "One of " + ' and '.join(fields) + " is required.")
                one_field_found = True
        return data


class ListInstituteStudentInputValidator(serializers.Serializer):
    skip = serializers.IntegerField(validators=[MinValueValidator(0)])
    take = serializers.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(100)])
    sort_by = serializers.CharField(
        validators=[institute_validators.institute_student_sort_by_validator])


class InstituteStudentSerializerForExamStat(serializers.ModelSerializer):
    class Meta:
        model = InstituteStudent
        fields = ['first_name', 'last_name', 'email', 'phone']


class GetInstituteStudentSerializer(serializers.ModelSerializer):
    referer_institute_student_identity = serializers.SerializerMethodField(
        'rename_referer_identity')
    wikiazma_institute_student_identity = serializers.SerializerMethodField(
        'rename_id')

    class Meta:
        model = InstituteStudent
        fields = ['wikiazma_institute_student_identity', 'referer_institute_student_identity', 'first_name', 'last_name', 'email', 'phone',
                  'info']

    def rename_referer_identity(self, obj):
        return obj.referer_identity

    def rename_id(self, obj):
        return obj.id


class ListInstituteSerializerForCollaboratorsAndQuestionBank(serializers.ModelSerializer):

    owner = serializers.SerializerMethodField(method_name='owner_info')

    def owner_info(self, obj):
        return UserSerializerForExam(obj.user).data

    class Meta:
        model = Institute
        fields = ['id', 'name', 'description', 'logo', 'logo_thumbnail', 'poster', 'poster_thumbnail', 'info',
                  'on_exam_finished_redirect_url',
                  'sandbox', 'created_at', 'modified_at', 'owner']


class SafeInstituteSerializerForExam(serializers.ModelSerializer):
    """
    This serializer class takes one or more Institute records and serializes them to json with desired fields.
    """

    owner = serializers.SerializerMethodField(method_name='owner_info')

    def owner_info(self, obj):
        return UserSerializerForExam(obj.user).data

    class Meta:
        model = Institute
        fields = ['id', 'name', 'description', 'logo', 'sandbox', 'owner']


class InstituteBalanceInputSerialize(serializers.Serializer):
    institute_id = serializers.CharField(
        validators=[main_validators.uuid_validator])
