from rest_framework import serializers
from .models import (
    Teacher, 
    Speciality, 
    SchoolClass, 
    Planning, 
    LEVEL_CHOICES, 
    Discount, 
    Fee, 
    PaymentPlan, 
    PaymentMode,
    EstablishmentCompetency, 
    Competency,
    Evaluation
)
from Auth.models import Profile, ProfileRole
from Subscriptions.models import Student, StudentEvaluation
from Establishment.models import Establishment
from Auth.serializers import ProfileRoleSerializer
from N3wtSchool import settings
from django.utils import timezone
import pytz


class CompetencySerializer(serializers.ModelSerializer):
    class Meta:
        model = Competency
        fields = '__all__'

class EstablishmentCompetencySerializer(serializers.ModelSerializer):
    class Meta:
        model = EstablishmentCompetency
        fields = '__all__'

class SpecialitySerializer(serializers.ModelSerializer):
    updated_date_formatted = serializers.SerializerMethodField()

    class Meta:
        model = Speciality
        fields = '__all__'

    def get_updated_date_formatted(self, obj):
        utc_time = timezone.localtime(obj.updated_date) # 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")

class TeacherDetailSerializer(serializers.ModelSerializer):
    specialities = SpecialitySerializer(many=True, read_only=True)

    class Meta:
        model = Teacher
        fields = ['id', 'last_name', 'first_name', 'email', 'specialities']

class TeacherSerializer(serializers.ModelSerializer):
    specialities = serializers.PrimaryKeyRelatedField(queryset=Speciality.objects.all(), many=True, required=False)
    specialities_details = serializers.SerializerMethodField()
    updated_date_formatted = serializers.SerializerMethodField()
    role_type = serializers.SerializerMethodField()
    profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False)
    profile_role_data = ProfileRoleSerializer(write_only=True, required=False)
    associated_profile_email = serializers.SerializerMethodField()
    profile = serializers.SerializerMethodField()

    class Meta:
        model = Teacher
        fields = '__all__'

    def create_or_update_teacher(self, teacher_data):
        profile_role_data = teacher_data.pop('profile_role_data', None)
        profile_role = teacher_data.pop('profile_role', None)

        # Gestion du ProfileRole
        if profile_role_data:
            # Vérifiez si 'profile' est un objet ou une clé primaire
            if isinstance(profile_role_data.get('profile'), Profile):
                profile_role_data['profile'] = profile_role_data['profile'].id
            establishment_id = profile_role_data.pop('establishment').id
            profile_role_data['establishment'] = establishment_id

            # Vérifiez si un ID est fourni pour une mise à jour
            profile_role_id = profile_role_data.get('id')
            if profile_role_id:
                # Mettre à jour un ProfileRole existant
                try:
                    profile_role_instance = ProfileRole.objects.get(id=profile_role_id)
                    profile_role_serializer = ProfileRoleSerializer(profile_role_instance, data=profile_role_data)
                    profile_role_serializer.is_valid(raise_exception=True)
                    profile_role = profile_role_serializer.save()
                except ProfileRole.DoesNotExist:
                    raise serializers.ValidationError({"profile_role_data": f"ProfileRole with id {profile_role_id} does not exist."})
            else:
                # Créer un nouveau ProfileRole
                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:
            # Récupérer un ProfileRole existant
            profile_role = ProfileRole.objects.get(id=profile_role.id)

        if profile_role:
            teacher_data['profile_role'] = profile_role

        # Vérifier si un Teacher existe déjà pour ce profile_role
        teacher_instance = Teacher.objects.filter(profile_role=profile_role).first()

        if teacher_instance:
            # Mettre à jour les champs existants
            for key, value in teacher_data.items():
                setattr(teacher_instance, key, value)
            teacher_instance.save()
            created = False
        else:
            # Créer un nouveau Teacher
            teacher_instance = Teacher.objects.create(**teacher_data)
            created = True

        return teacher_instance

    def create(self, validated_data):
        specialities_data = validated_data.pop('specialities', [])
        teacher_instance = self.create_or_update_teacher(validated_data)

        # Associer les spécialités
        if specialities_data:
            teacher_instance.specialities.set(specialities_data)

        return teacher_instance

    def update(self, instance, validated_data):
        specialities_data = validated_data.pop('specialities', [])
        teacher_instance = self.create_or_update_teacher(validated_data)

        # Mettre à jour les spécialités
        if specialities_data:
            teacher_instance.specialities.set(specialities_data)

        return teacher_instance

    def get_updated_date_formatted(self, obj):
        utc_time = timezone.localtime(obj.updated_date) # 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_specialities_details(self, obj):
        return [{'id': speciality.id, 'name': speciality.name, 'color_code': speciality.color_code} for speciality in obj.specialities.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

    def get_role_type(self, obj):
        if obj.profile_role:
            return obj.profile_role.role_type
        return None

    def get_profile(self, obj):
        # Retourne l'id du profile associé via profile_role
        if obj.profile_role and obj.profile_role.profile:
            return obj.profile_role.profile.id
        return None

class PlanningSerializer(serializers.ModelSerializer):
    class Meta:
        model = Planning
        fields = ['id', 'level', 'schedule']

    def to_internal_value(self, data):
        internal_value = super().to_internal_value(data)
        internal_value['schedule'] = data.get('schedule', {})
        return internal_value

class StudentDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = ['id', 'last_name', 'first_name', 'photo', 'level']

class SchoolClassSerializer(serializers.ModelSerializer):
    updated_date_formatted = serializers.SerializerMethodField()
    teachers = serializers.PrimaryKeyRelatedField(queryset=Teacher.objects.all(), many=True, required=False)
    establishment = serializers.PrimaryKeyRelatedField(queryset=Establishment.objects.all(), required=False)
    teachers_details = serializers.SerializerMethodField()
    students = serializers.SerializerMethodField()

    class Meta:
        model = SchoolClass
        fields = '__all__'

    def get_students(self, obj):
        # Filtrer uniquement les étudiants dont le dossier est validé (status = 5)
        validated_students = obj.students.filter(registrationform__status=5)
        return StudentDetailSerializer(validated_students, many=True).data

    def create(self, validated_data):
        teachers_data = validated_data.pop('teachers', [])
        levels_data = validated_data.pop('levels', [])
        plannings_data = validated_data.pop('plannings', [])

        school_class = SchoolClass.objects.create(
            atmosphere_name=validated_data.get('atmosphere_name', ''),
            age_range=validated_data.get('age_range', []),
            number_of_students=validated_data.get('number_of_students', 0),
            teaching_language=validated_data.get('teaching_language', ''),
            school_year=validated_data.get('school_year', ''),
            type=validated_data.get('type', 1),
            time_range=validated_data.get('time_range', ['08:30', '17:30']),
            opening_days=validated_data.get('opening_days', [1, 2, 4, 5]),
            establishment=validated_data.get('establishment', None)
        )

        school_class.teachers.set(teachers_data)
        school_class.levels.set(levels_data)

        for planning_data in plannings_data:
            Planning.objects.create(
                school_class=school_class,
                level=planning_data['level'],
                schedule=planning_data.get('schedule', {})
            )

        return school_class

    def update(self, instance, validated_data):
        teachers_data = validated_data.pop('teachers', [])
        levels_data = validated_data.pop('levels', [])
        plannings_data = validated_data.pop('plannings', [])

        instance.atmosphere_name = validated_data.get('atmosphere_name', instance.atmosphere_name)
        instance.age_range = validated_data.get('age_range', instance.age_range)
        instance.number_of_students = validated_data.get('number_of_students', instance.number_of_students)
        instance.teaching_language = validated_data.get('teaching_language', instance.teaching_language)
        instance.school_year = validated_data.get('school_year', instance.school_year)
        instance.type = validated_data.get('type', instance.type)
        instance.time_range = validated_data.get('time_range', instance.time_range)
        instance.opening_days = validated_data.get('opening_days', instance.opening_days)
        instance.establishment = validated_data.get('establishment', instance.establishment)

        instance.save()
        instance.teachers.set(teachers_data)
        instance.levels.set(levels_data)

        existing_plannings = {planning.level: planning for planning in instance.plannings.all()}

        for planning_data in plannings_data:
            level = planning_data['level']
            if level in existing_plannings:
                # Update existing planning
                planning = existing_plannings[level]
                planning.schedule = planning_data.get('schedule', planning.schedule)
                planning.save()
            else:
                # Create new planning if level not existing
                Planning.objects.create(
                    school_class=instance,
                    level=level,
                    schedule=planning_data.get('schedule', {})
                )

        return instance

    def get_teachers_details(self, obj):
        return [{'id': teacher.id, 'last_name': teacher.last_name, 'first_name': teacher.first_name} for teacher in obj.teachers.all()]

    def get_updated_date_formatted(self, obj):
        utc_time = timezone.localtime(obj.updated_date)
        local_tz = pytz.timezone(settings.TZ_APPLI)
        local_time = utc_time.astimezone(local_tz)
        return local_time.strftime("%d-%m-%Y %H:%M")

class DiscountSerializer(serializers.ModelSerializer):
    updated_at_formatted = serializers.SerializerMethodField()
    establishment = serializers.PrimaryKeyRelatedField(queryset=Establishment.objects.all(), required=False)
    class Meta:
        model = Discount
        fields = '__all__'

    def get_updated_at_formatted(self, obj):
        utc_time = timezone.localtime(obj.updated_at)
        local_tz = pytz.timezone(settings.TZ_APPLI)
        local_time = utc_time.astimezone(local_tz)
        return local_time.strftime("%d-%m-%Y %H:%M")

class FeeSerializer(serializers.ModelSerializer):
    updated_at_formatted = serializers.SerializerMethodField()
    establishment = serializers.PrimaryKeyRelatedField(queryset=Establishment.objects.all(), required=False)

    class Meta:
        model = Fee
        fields = '__all__'

    def get_updated_at_formatted(self, obj):
        utc_time = timezone.localtime(obj.updated_at)
        local_tz = pytz.timezone(settings.TZ_APPLI)
        local_time = utc_time.astimezone(local_tz)
        return local_time.strftime("%d-%m-%Y %H:%M")

class PaymentPlanSerializer(serializers.ModelSerializer):
    class Meta:
        model = PaymentPlan
        fields = '__all__'

class PaymentModeSerializer(serializers.ModelSerializer):
    class Meta:
        model = PaymentMode
        fields = '__all__'


class EvaluationSerializer(serializers.ModelSerializer):
    speciality_name = serializers.CharField(source='speciality.name', read_only=True)
    speciality_color = serializers.CharField(source='speciality.color_code', read_only=True)
    school_class_name = serializers.CharField(source='school_class.atmosphere_name', read_only=True)
    
    class Meta:
        model = Evaluation
        fields = '__all__'


class StudentEvaluationSerializer(serializers.ModelSerializer):
    student_name = serializers.SerializerMethodField()
    student_first_name = serializers.CharField(source='student.first_name', read_only=True)
    student_last_name = serializers.CharField(source='student.last_name', read_only=True)
    evaluation_name = serializers.CharField(source='evaluation.name', read_only=True)
    max_score = serializers.DecimalField(source='evaluation.max_score', read_only=True, max_digits=5, decimal_places=2)
    speciality_name = serializers.CharField(source='evaluation.speciality.name', read_only=True)
    speciality_color = serializers.CharField(source='evaluation.speciality.color', read_only=True)
    period = serializers.CharField(source='evaluation.period', read_only=True)
    
    class Meta:
        model = StudentEvaluation
        fields = '__all__'
    
    def get_student_name(self, obj):
        return f"{obj.student.last_name} {obj.student.first_name}"