from rest_framework import serializers
from .models import RegistrationFileGroup, RegistrationForm, Student, Guardian, Sibling, Language, RegistrationTemplateMaster, RegistrationTemplate
from School.models import SchoolClass, Fee, Discount, FeeType
from School.serializers import FeeSerializer, DiscountSerializer
from Auth.models import ProfileRole, Profile
from Auth.serializers import ProfileSerializer, ProfileRoleSerializer
from GestionMessagerie.models import Messagerie
from GestionNotification.models import Notification
from N3wtSchool import settings
from django.utils import timezone
import pytz
from datetime import datetime

class RegistrationTemplateMasterSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    class Meta:
        model = RegistrationTemplateMaster
        fields = '__all__'

class RegistrationTemplateSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    class Meta:
        model = RegistrationTemplate
        fields = '__all__'

class GuardianSimpleSerializer(serializers.ModelSerializer):
    associated_profile_email = serializers.SerializerMethodField()

    class Meta:
        model = Guardian
        fields = ['id', 'associated_profile_email']

    def get_associated_profile_email(self, obj):
        if obj.profile_role and obj.profile_role.profile:
            return obj.profile_role.profile.email
        return None

class RegistrationFormSimpleSerializer(serializers.ModelSerializer):
    guardians = GuardianSimpleSerializer(many=True, source='student.guardians')
    last_name = serializers.SerializerMethodField()
    first_name = serializers.SerializerMethodField()

    class Meta:
        model = RegistrationForm
        fields = ['student_id', 'last_name', 'first_name', 'guardians']
    
    def get_last_name(self, obj):
        return obj.student.last_name

    def get_first_name(self, obj):
        return obj.student.first_name

class RegistrationFileGroupSerializer(serializers.ModelSerializer):
    registration_forms = serializers.SerializerMethodField()

    class Meta:
        model = RegistrationFileGroup
        fields = '__all__'

    def get_registration_forms(self, obj):
        forms = RegistrationForm.objects.filter(fileGroup=obj)
        return RegistrationFormSimpleSerializer(forms, many=True).data

class LanguageSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    class Meta:
        model = Language
        fields = '__all__'

class SiblingSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    class Meta:
        model = Sibling
        fields = '__all__'

class GuardianSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False)
    profile_role_data = ProfileRoleSerializer(write_only=True, required=False)
    associated_profile_email = serializers.SerializerMethodField()

    class Meta:
        model = Guardian
        fields = '__all__'

    def get_associated_profile_email(self, obj):
        if obj.profile_role and obj.profile_role.profile:
            return obj.profile_role.profile.email
        return None

class StudentSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    guardians = GuardianSerializer(many=True, required=False)
    siblings = SiblingSerializer(many=True, required=False)
    spoken_languages = LanguageSerializer(many=True, required=False)
    associated_class_id = serializers.PrimaryKeyRelatedField(queryset=SchoolClass.objects.all(), source='associated_class', required=False, write_only=False, read_only=False)
    age = serializers.SerializerMethodField()
    formatted_birth_date = serializers.SerializerMethodField()
    birth_date = serializers.DateField(input_formats=['%d-%m-%Y', '%Y-%m-%d'], required=False, allow_null=True)
    associated_class_name = serializers.SerializerMethodField()

    class Meta:
        model = Student
        fields = '__all__'

    def create_or_update_guardians(self, guardians_data):
        guardians_ids = []
        for guardian_data in guardians_data:
            profile_role_data = guardian_data.pop('profile_role_data', None)
            profile_role = guardian_data.pop('profile_role', None)

            if profile_role_data:
                establishment_id = profile_role_data.pop('establishment').id
                profile_role_data['establishment'] = establishment_id

                profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
                profile_role_serializer.is_valid(raise_exception=True)
                profile_role = profile_role_serializer.save()
            elif profile_role:
                profile_role = ProfileRole.objects.get(id=profile_role.id)

            if profile_role:
                guardian_data['profile_role'] = profile_role

            guardian_instance, created = Guardian.objects.update_or_create(
                id=guardian_data.get('id'),
                defaults=guardian_data
            )
            guardians_ids.append(guardian_instance.id)
        return guardians_ids

    def create_or_update_siblings(self, siblings_data):
        siblings_ids = []
        for sibling_data in siblings_data:
            sibling_instance, created = Sibling.objects.update_or_create(
                id=sibling_data.get('id'),
                defaults=sibling_data
            )
            siblings_ids.append(sibling_instance.id)
        return siblings_ids

    def create_or_update_languages(self, languages_data):
        languages_ids = []
        for language_data in languages_data:
            language_instance, created = Language.objects.update_or_create(
                id=language_data.get('id'),
                defaults=language_data
            )
            languages_ids.append(language_instance.id)
        return languages_ids

    def create(self, validated_data):
        guardians_data = validated_data.pop('guardians', [])
        siblings_data = validated_data.pop('siblings', [])
        languages_data = validated_data.pop('spoken_languages', [])
        student = Student.objects.create(**validated_data)
        student.guardians.set(self.create_or_update_guardians(guardians_data))
        student.siblings.set(self.create_or_update_siblings(siblings_data))
        student.spoken_languages.set(self.create_or_update_languages(languages_data))

        return student

    def update(self, instance, validated_data):
        guardians_data = validated_data.pop('guardians', [])
        siblings_data = validated_data.pop('siblings', [])
        languages_data = validated_data.pop('spoken_languages', [])
        if guardians_data:
            instance.guardians.set(self.create_or_update_guardians(guardians_data))
        if siblings_data:
            instance.siblings.set(self.create_or_update_siblings(siblings_data))
        if languages_data:
            instance.spoken_languages.set(self.create_or_update_languages(languages_data))

        for field in self.fields:
            try:
                setattr(instance, field, validated_data[field])
            except KeyError:
                pass
        instance.save()

        return instance

    def get_age(self, obj):
        return obj.age

    def get_formatted_birth_date(self, obj):
        return obj.formatted_birth_date

    def get_associated_class_name(self, obj):
        return obj.associated_class.atmosphereName if obj.associated_class else None

class RegistrationFormSerializer(serializers.ModelSerializer):
    student = StudentSerializer(many=False, required=False)
    registration_file = serializers.FileField(required=False)
    status_label = serializers.SerializerMethodField()
    formatted_last_update = serializers.SerializerMethodField()
    registration_files = RegistrationTemplateSerializer(many=True, required=False)
    fees = serializers.PrimaryKeyRelatedField(queryset=Fee.objects.all(), many=True, required=False)
    discounts = serializers.PrimaryKeyRelatedField(queryset=Discount.objects.all(), many=True, required=False)
    totalRegistrationFees = serializers.SerializerMethodField()
    totalTuitionFees = serializers.SerializerMethodField()

    class Meta:
        model = RegistrationForm
        fields = '__all__'

    def create(self, validated_data):
        student_data = validated_data.pop('student')
        student = StudentSerializer.create(StudentSerializer(), student_data)
        fees_data = validated_data.pop('fees', [])
        discounts_data = validated_data.pop('discounts', [])
        registrationForm = RegistrationForm.objects.create(student=student, **validated_data)

        # Associer les IDs des objets Fee et Discount au RegistrationForm
        registrationForm.fees.set([fee.id for fee in fees_data])
        registrationForm.discounts.set([discount.id for discount in discounts_data])
        return registrationForm

    def update(self, instance, validated_data):
        student_data = validated_data.pop('student', None)
        fees_data = validated_data.pop('fees', [])
        discounts_data = validated_data.pop('discounts', [])
        if student_data:
            student = instance.student
            StudentSerializer.update(StudentSerializer(), student, student_data)

        for field in self.fields:
            try:
                setattr(instance, field, validated_data[field])
            except KeyError:
                pass
        instance.save()

        # Associer les IDs des objets Fee et Discount au RegistrationForm
        instance.fees.set([fee.id for fee in fees_data])
        instance.discounts.set([discount.id for discount in discounts_data])

        return instance

    def get_status_label(self, obj):
        return obj.get_status_display()

    def get_formatted_last_update(self, obj):
        utc_time = timezone.localtime(obj.last_update) # Convert to local time
        local_tz = pytz.timezone(settings.TZ_APPLI)
        local_time = utc_time.astimezone(local_tz)

        return local_time.strftime("%d-%m-%Y %H:%M")

    def get_totalRegistrationFees(self, obj):
        return sum(fee.base_amount for fee in obj.fees.filter(type=FeeType.REGISTRATION_FEE))

    def get_totalTuitionFees(self, obj):
        return sum(fee.base_amount for fee in obj.fees.filter(type=FeeType.TUITION_FEE))

class StudentByParentSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)

    class Meta:
        model = Student
        fields = ['id', 'last_name', 'first_name']

    def __init__(self, *args, **kwargs):
        super(StudentByParentSerializer, self).__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].required = False

class RegistrationFormByParentSerializer(serializers.ModelSerializer):
    student = StudentByParentSerializer(many=False, required=True)

    class Meta:
        model = RegistrationForm
        fields = ['student', 'status']

    def __init__(self, *args, **kwargs):
        super(RegistrationFormByParentSerializer, self).__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].required = False

class GuardianByDICreationSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    associated_profile_email = serializers.SerializerMethodField()

    class Meta:
        model = Guardian
        fields = ['id', 'last_name', 'first_name', 'associated_profile_email']

    def get_associated_profile_email(self, obj):
        if obj.profile_role and obj.profile_role.profile:
            return obj.profile_role.profile.email
        return None

class StudentByRFCreationSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    guardians = GuardianByDICreationSerializer(many=True, required=False)

    class Meta:
        model = Student
        fields = ['id', 'last_name', 'first_name', 'guardians']

    def __init__(self, *args, **kwargs):
        super(StudentByRFCreationSerializer, self).__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].required = False

class NotificationSerializer(serializers.ModelSerializer):
    notification_type_label = serializers.ReadOnlyField()

    class Meta:
        model = Notification
        fields = '__all__'
