from django.http.response import JsonResponse
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from .models import (
    Teacher,
    Speciality,
    SchoolClass,
    Planning,
    Discount,
    Fee,
    FeeType,
    PaymentPlan,
    PaymentMode,
    EstablishmentCompetency,
    Competency,
    Evaluation
)
from .serializers import (
    TeacherSerializer,
    SpecialitySerializer,
    SchoolClassSerializer,
    PlanningSerializer,
    DiscountSerializer,
    FeeSerializer,
    PaymentPlanSerializer,
    PaymentModeSerializer,
    EstablishmentCompetencySerializer,
    CompetencySerializer,
    EvaluationSerializer,
    StudentEvaluationSerializer
)
from Common.models import Domain, Category
from N3wtSchool.bdd import delete_object, getAllObjects, getObject
from django.db.models import Q
from collections import defaultdict
from Subscriptions.models import Student, StudentCompetency, StudentEvaluation
from Subscriptions.util import getCurrentSchoolYear, getNextSchoolYear, getHistoricalYears
import logging
from N3wtSchool.mailManager import sendRegisterForm, sendRegisterTeacher

logger = logging.getLogger(__name__)


@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class SchoolYearsListView(APIView):
    """
    Liste les années scolaires disponibles pour l'historique.
    Retourne l'année en cours, la suivante, et les années historiques.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        current_year = getCurrentSchoolYear()
        next_year = getNextSchoolYear()
        historical_years = getHistoricalYears(5)
        
        return JsonResponse({
            'current_year': current_year,
            'next_year': next_year,
            'historical_years': historical_years,
            'all_years': [next_year, current_year] + historical_years
        }, safe=False)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class SpecialityListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        establishment_id = request.GET.get('establishment_id', None)
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        specialities_list = getAllObjects(Speciality)
        if establishment_id:
            specialities_list = specialities_list.filter(establishment__id=establishment_id).distinct()
        specialities_serializer = SpecialitySerializer(specialities_list, many=True)
        return JsonResponse(specialities_serializer.data, safe=False)

    def post(self, request):
        speciality_data=JSONParser().parse(request)
        speciality_serializer = SpecialitySerializer(data=speciality_data)

        if speciality_serializer.is_valid():
            speciality_serializer.save()
            return JsonResponse(speciality_serializer.data, safe=False, status=status.HTTP_201_CREATED)

        return JsonResponse(speciality_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class SpecialityDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        speciality = getObject(_objectName=Speciality, _columnName='id', _value=id)
        speciality_serializer=SpecialitySerializer(speciality)
        return JsonResponse(speciality_serializer.data, safe=False)

    def put(self, request, id):
        speciality_data=JSONParser().parse(request)
        speciality = getObject(_objectName=Speciality, _columnName='id', _value=id)
        speciality_serializer = SpecialitySerializer(speciality, data=speciality_data)
        if speciality_serializer.is_valid():
            speciality_serializer.save()
            return JsonResponse(speciality_serializer.data, safe=False)

        return JsonResponse(speciality_serializer.errors, safe=False)

    def delete(self, request, id):
        return delete_object(Speciality, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class TeacherListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        establishment_id = request.GET.get('establishment_id', None)
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        teachers_list = getAllObjects(Teacher)
        if teachers_list:
            teachers_list = teachers_list.filter(profile_role__establishment_id=establishment_id)
        teachers_serializer = TeacherSerializer(teachers_list, many=True)
        return JsonResponse(teachers_serializer.data, safe=False)

    def post(self, request):
        teacher_data=JSONParser().parse(request)
        teacher_serializer = TeacherSerializer(data=teacher_data)

        if teacher_serializer.is_valid():
            teacher_instance = teacher_serializer.save()
            # Envoi du mail d'inscription enseignant uniquement à la création
            email = None
            establishment_id = None
            if hasattr(teacher_instance, "profile_role") and teacher_instance.profile_role:
                if hasattr(teacher_instance.profile_role, "profile") and teacher_instance.profile_role.profile:
                    email = teacher_instance.profile_role.profile.email
                if hasattr(teacher_instance.profile_role, "establishment") and teacher_instance.profile_role.establishment:
                    establishment_id = teacher_instance.profile_role.establishment.id
            if email and establishment_id:
                sendRegisterTeacher(email, establishment_id)
            return JsonResponse(teacher_serializer.data, safe=False)

        return JsonResponse(teacher_serializer.errors, safe=False)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class TeacherDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get (self, request, id):
        teacher = getObject(_objectName=Teacher, _columnName='id', _value=id)
        teacher_serializer=TeacherSerializer(teacher)

        return JsonResponse(teacher_serializer.data, safe=False)

    def put(self, request, id):
        teacher_data = JSONParser().parse(request)
        teacher = getObject(_objectName=Teacher, _columnName='id', _value=id)

        # Récupérer l'ancien profile avant modification
        old_profile_role = getattr(teacher, 'profile_role', None)
        old_profile = getattr(old_profile_role, 'profile', None) if old_profile_role else None

        teacher_serializer = TeacherSerializer(teacher, data=teacher_data)
        if teacher_serializer.is_valid():
            teacher_serializer.save()

            # Après modification, vérifier si l'ancien profile n'a plus de ProfileRole
            if old_profile:
                from Auth.models import ProfileRole  # import local pour éviter les imports circulaires
                if not ProfileRole.objects.filter(profile=old_profile).exists():
                    old_profile.delete()

            return JsonResponse(teacher_serializer.data, safe=False)

        return JsonResponse(teacher_serializer.errors, safe=False)

    def delete(self, request, id):
        # Suppression du Teacher et du ProfileRole associé
        teacher = getObject(_objectName=Teacher, _columnName='id', _value=id)
        profile_role = getattr(teacher, 'profile_role', None)
        profile = getattr(profile_role, 'profile', None) if profile_role else None

        # Supprime le Teacher (ce qui supprime le ProfileRole via on_delete=models.CASCADE)
        response = delete_object(Teacher, id, related_field='profile_role')

        # Si un profile était associé, vérifier s'il reste des ProfileRole
        if profile:
            from Auth.models import ProfileRole  # import local pour éviter les imports circulaires
            if not ProfileRole.objects.filter(profile=profile).exists():
                profile.delete()

        return response

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class SchoolClassListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        establishment_id = request.GET.get('establishment_id', None)
        school_year = request.GET.get('school_year', None)
        year_filter = request.GET.get('year_filter', None)  # 'current_year', 'next_year', 'historical'
        
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        school_classes_list = getAllObjects(SchoolClass)
        if school_classes_list:
            school_classes_list = school_classes_list.filter(establishment=establishment_id)
            
            # Filtrage par année scolaire
            if school_year:
                school_classes_list = school_classes_list.filter(school_year=school_year)
            elif year_filter:
                current_year = getCurrentSchoolYear()
                next_year = getNextSchoolYear()
                historical_years = getHistoricalYears(5)
                
                if year_filter == 'current_year':
                    school_classes_list = school_classes_list.filter(school_year=current_year)
                elif year_filter == 'next_year':
                    school_classes_list = school_classes_list.filter(school_year=next_year)
                elif year_filter == 'historical':
                    school_classes_list = school_classes_list.filter(school_year__in=historical_years)
            
            school_classes_list = school_classes_list.distinct()
            
        classes_serializer = SchoolClassSerializer(school_classes_list, many=True)
        return JsonResponse(classes_serializer.data, safe=False)

    def post(self, request):
        classe_data=JSONParser().parse(request)
        classe_serializer = SchoolClassSerializer(data=classe_data)

        if classe_serializer.is_valid():
            classe_serializer.save()
            return JsonResponse(classe_serializer.data, safe=False)

        return JsonResponse(classe_serializer.errors, safe=False)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class SchoolClassDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get (self, request, id):
        schoolClass = getObject(_objectName=SchoolClass, _columnName='id', _value=id)
        classe_serializer=SchoolClassSerializer(schoolClass)

        return JsonResponse(classe_serializer.data, safe=False)

    def put(self, request, id):
        classe_data=JSONParser().parse(request)
        schoolClass = getObject(_objectName=SchoolClass, _columnName='id', _value=id)
        classe_serializer = SchoolClassSerializer(schoolClass, data=classe_data)
        if classe_serializer.is_valid():
            classe_serializer.save()
            return JsonResponse(classe_serializer.data, safe=False)

        return JsonResponse(classe_serializer.errors, safe=False)

    def delete(self, request, id):
        return delete_object(SchoolClass, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class PlanningListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        schedulesList=getAllObjects(Planning)
        schedules_serializer=PlanningSerializer(schedulesList, many=True)
        return JsonResponse(schedules_serializer.data, safe=False)

    def post(self, request):
        planning_data=JSONParser().parse(request)
        planning_serializer = PlanningSerializer(data=planning_data)

        if planning_serializer.is_valid():
            planning_serializer.save()
            return JsonResponse(planning_serializer.data, safe=False)

        return JsonResponse(planning_serializer.errors, safe=False)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class PlanningDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get (self, request, id):
        planning = getObject(_objectName=Planning, _columnName='classe_id', _value=id)
        planning_serializer=PlanningSerializer(planning)

        return JsonResponse(planning_serializer.data, safe=False)

    def put(self, request, id):
        planning_data = JSONParser().parse(request)

        try:
            planning = Planning.objects.get(id=id)
        except Planning.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        except Planning.MultipleObjectsReturned:
            return JsonResponse({'error': 'Multiple objects found'}, status=status.HTTP_400_BAD_REQUEST)

        planning_serializer = PlanningSerializer(planning, data=planning_data)

        if planning_serializer.is_valid():
            planning_serializer.save()
            return JsonResponse(planning_serializer.data, safe=False)

        return JsonResponse(planning_serializer.errors, safe=False)

    def delete(self, request, id):
        return delete_object(Planning, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class FeeListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        establishment_id = request.GET.get('establishment_id', None)
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        filter = request.GET.get('filter', '').strip()
        if filter not in ('registration', 'tuition'):
            return JsonResponse(
                {'error': "Le paramètre 'filter' doit être 'registration' ou 'tuition'"},
                safe=False,
                status=status.HTTP_400_BAD_REQUEST,
            )
        fee_type_value = FeeType.REGISTRATION_FEE if filter == 'registration' else FeeType.TUITION_FEE

        fees = Fee.objects.filter(type=fee_type_value, establishment_id=establishment_id).distinct()
        fee_serializer = FeeSerializer(fees, many=True)

        return JsonResponse(fee_serializer.data, safe=False, status=status.HTTP_200_OK)

    def post(self, request):
        fee_data = JSONParser().parse(request)
        fee_serializer = FeeSerializer(data=fee_data)
        if fee_serializer.is_valid():
            fee_serializer.save()
            return JsonResponse(fee_serializer.data, safe=False, status=status.HTTP_201_CREATED)
        return JsonResponse(fee_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class FeeDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            fee = Fee.objects.get(id=id)
            fee_serializer = FeeSerializer(fee)
            return JsonResponse(fee_serializer.data, safe=False)
        except Fee.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        fee_data = JSONParser().parse(request)
        try:
            fee = Fee.objects.get(id=id)
        except Fee.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        fee_serializer = FeeSerializer(fee, data=fee_data, partial=True)
        if fee_serializer.is_valid():
            fee_serializer.save()
            return JsonResponse(fee_serializer.data, safe=False)
        return JsonResponse(fee_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        return delete_object(Fee, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class DiscountListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        establishment_id = request.GET.get('establishment_id', None)
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        filter = request.GET.get('filter', '').strip()
        discount_type_value = 0 if filter == 'registration' else 1

        discounts = Discount.objects.filter(type=discount_type_value, establishment_id=establishment_id).distinct()
        discounts_serializer = DiscountSerializer(discounts, many=True)

        return JsonResponse(discounts_serializer.data, safe=False, status=status.HTTP_200_OK)

    def post(self, request):
        discount_data = JSONParser().parse(request)
        discount_serializer = DiscountSerializer(data=discount_data)
        if discount_serializer.is_valid():
            discount_serializer.save()
            return JsonResponse(discount_serializer.data, safe=False, status=status.HTTP_201_CREATED)
        return JsonResponse(discount_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class DiscountDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            discount = Discount.objects.get(id=id)
            discount_serializer = DiscountSerializer(discount)
            return JsonResponse(discount_serializer.data, safe=False)
        except Discount.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        discount_data = JSONParser().parse(request)
        try:
            discount = Discount.objects.get(id=id)
        except Discount.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        discount_serializer = DiscountSerializer(discount, data=discount_data, partial=True)  # Utilisation de partial=True
        if discount_serializer.is_valid():
            discount_serializer.save()
            return JsonResponse(discount_serializer.data, safe=False)
        return JsonResponse(discount_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        return delete_object(Discount, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class PaymentPlanListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        establishment_id = request.GET.get('establishment_id', None)
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        filter = request.GET.get('filter', '').strip()
        type_value = 0 if filter == 'registration' else 1

        payment_plans = PaymentPlan.objects.filter(type=type_value, establishment_id=establishment_id).distinct()
        payment_plans_serializer = PaymentPlanSerializer(payment_plans, many=True)

        return JsonResponse(payment_plans_serializer.data, safe=False, status=status.HTTP_200_OK)

    def post(self, request):
        payment_plan_data = JSONParser().parse(request)
        payment_plan_serializer = PaymentPlanSerializer(data=payment_plan_data)
        if payment_plan_serializer.is_valid():
            payment_plan_serializer.save()
            return JsonResponse(payment_plan_serializer.data, safe=False, status=status.HTTP_201_CREATED)
        return JsonResponse(payment_plan_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class PaymentPlanDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            payment_plan = PaymentPlan.objects.get(id=id)
            payment_plan_serializer = PaymentPlanSerializer(payment_plan)
            return JsonResponse(payment_plan_serializer.data, safe=False)
        except PaymentPlan.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        payment_plan_data = JSONParser().parse(request)
        try:
            payment_plan = PaymentPlan.objects.get(id=id)
        except PaymentPlan.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        payment_plan_serializer = PaymentPlanSerializer(payment_plan, data=payment_plan_data, partial=True)
        if payment_plan_serializer.is_valid():
            payment_plan_serializer.save()
            return JsonResponse(payment_plan_serializer.data, safe=False)
        return JsonResponse(payment_plan_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        return delete_object(PaymentPlan, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class PaymentModeListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        establishment_id = request.GET.get('establishment_id', None)
        if establishment_id is None:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        filter = request.GET.get('filter', '').strip()
        type_value = 0 if filter == 'registration' else 1

        payment_modes = PaymentMode.objects.filter(type=type_value, establishment_id=establishment_id).distinct()
        payment_modes_serializer = PaymentModeSerializer(payment_modes, many=True)

        return JsonResponse(payment_modes_serializer.data, safe=False, status=status.HTTP_200_OK)

    def post(self, request):
        payment_mode_data = JSONParser().parse(request)
        payment_mode_serializer = PaymentModeSerializer(data=payment_mode_data)
        if payment_mode_serializer.is_valid():
            payment_mode_serializer.save()
            return JsonResponse(payment_mode_serializer.data, safe=False, status=status.HTTP_201_CREATED)
        return JsonResponse(payment_mode_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class PaymentModeDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            payment_mode = PaymentMode.objects.get(id=id)
            payment_mode_serializer = PaymentModeSerializer(payment_mode)
            return JsonResponse(payment_mode_serializer.data, safe=False)
        except PaymentMode.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        payment_mode_data = JSONParser().parse(request)
        try:
            payment_mode = PaymentMode.objects.get(id=id)
        except PaymentMode.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        payment_mode_serializer = PaymentModeSerializer(payment_mode, data=payment_mode_data, partial=True)
        if payment_mode_serializer.is_valid():
            payment_mode_serializer.save()
            return JsonResponse(payment_mode_serializer.data, safe=False)
        return JsonResponse(payment_mode_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        return delete_object(PaymentMode, id)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class CompetencyListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        cycle = request.GET.get('cycle')
        if cycle is None:
            return JsonResponse({'error': 'cycle est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        competencies_list = getAllObjects(Competency)
        competencies_list = competencies_list.filter(
            category__domain__cycle=cycle
        ).distinct()
        serializer = CompetencySerializer(competencies_list, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        data = JSONParser().parse(request)
        serializer = CompetencySerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
        return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class CompetencyDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            competency = Competency.objects.get(id=id)
            serializer = CompetencySerializer(competency)
            return JsonResponse(serializer.data, safe=False)
        except Competency.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        try:
            competency = Competency.objects.get(id=id)
        except Competency.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        data = JSONParser().parse(request)
        serializer = CompetencySerializer(competency, data=data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, safe=False)
        return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        try:
            competency = Competency.objects.get(id=id)
            competency.delete()
            return JsonResponse({'message': 'Deleted'}, safe=False)
        except Competency.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class EstablishmentCompetencyListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        establishment_id = request.GET.get('establishment_id')
        cycle = request.GET.get('cycle')
        if not establishment_id or not cycle:
            return JsonResponse({'error': 'establishment_id et cycle sont requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)

        # Toutes les compétences du cycle
        competencies = Competency.objects.filter(category__domain__cycle=cycle).select_related('category', 'category__domain')

        # Récupérer les EstablishmentCompetency pour l'établissement et le cycle
        ec_qs = EstablishmentCompetency.objects.filter(
                Q(competency__in=competencies) | Q(competency__isnull=True),
                establishment_id=establishment_id
            ).select_related('competency', 'custom_category')

        # Required = compétences de référence requises
        required_ids = set(ec_qs.filter(is_required=True, competency__isnull=False).values_list('competency_id', flat=True))

        # Custom = compétences custom (pas de lien vers Competency)
        custom_ecs = ec_qs.filter(is_required=False, competency__isnull=True)

        # Organisation par domaine > catégorie
        result = []
        selected_count = 0
        domaines = Domain.objects.filter(cycle=cycle)
        for domaine in domaines:
            domaine_dict = {
                "domaine_id": domaine.id,
                "domaine_nom": domaine.name,
                "categories": []
            }
            categories = domaine.categories.all()
            for categorie in categories:
                categorie_dict = {
                    "categorie_id": categorie.id,
                    "categorie_nom": categorie.name,
                    "competences": []
                }

                # Liste des noms de compétences custom pour cette catégorie
                custom_for_cat = custom_ecs.filter(custom_category=categorie)
                custom_names = set(ec.custom_name.strip().lower() for ec in custom_for_cat if ec.custom_name)

                # Compétences de référence (on saute celles qui sont déjà en custom)
                competences = categorie.competencies.all()
                for comp in competences:
                    if comp.name.strip().lower() in custom_names:
                        continue  # On n'affiche pas la compétence de référence si une custom du même nom existe
                    if comp.id in required_ids:
                        state = "required"
                        selected_count += 1
                    else:
                        state = "none"
                    categorie_dict["competences"].append({
                        "competence_id": comp.id,
                        "nom": comp.name,
                        "state": state
                    })

                # Ajout des compétences custom
                for ec in custom_for_cat:
                    categorie_dict["competences"].append({
                        "competence_id": ec.id,
                        "nom": ec.custom_name,
                        "state": "custom"
                    })
                    selected_count += 1

                domaine_dict["categories"].append(categorie_dict)
            result.append(domaine_dict)

        return JsonResponse({
            "selected_count": selected_count,
            "data": result
        }, safe=False)

    def post(self, request):
        """
        Crée une ou plusieurs compétences custom pour un établissement (is_required=False)
        Attendu dans le body :
        [
            { "establishment_id": ..., "category_id": ..., "nom": ... },
            ...
        ]
        """
        data = JSONParser().parse(request)
        # Si data est un dict (un seul objet), on le met dans une liste
        if isinstance(data, dict):
            data = [data]

        created = []
        errors = []

        for item in data:
            establishment_id = item.get("establishment_id")
            category_id = item.get("category_id")
            nom = item.get("nom")

            if not establishment_id or not category_id or not nom:
                errors.append({"error": "establishment_id, category_id et nom sont requis", "item": item})
                continue

            try:
                category = Category.objects.get(id=category_id)
                ec_exists = EstablishmentCompetency.objects.filter(
                    establishment_id=establishment_id,
                    competency__isnull=True,
                    custom_name=nom,
                ).exists()
                if ec_exists:
                    errors.append({"error": "Une compétence custom de ce nom existe déjà pour cet établissement", "item": item})
                    continue

                ec = EstablishmentCompetency.objects.create(
                    establishment_id=establishment_id,
                    competency=None,
                    custom_name=nom,
                    custom_category=category,
                    is_required=False
                )

                # Récupérer l'établissement et sa fréquence d'évaluation
                establishment = ec.establishment
                evaluation_frequency = establishment.evaluation_frequency  # 1=Trimestre, 2=Semestre, 3=Année

                # Déterminer l'année scolaire courante
                school_year = getCurrentSchoolYear()

                # Générer les périodes selon la fréquence
                periods = []
                if evaluation_frequency == 1:  # Trimestre
                    periods = [f"T{i+1}_{school_year}" for i in range(3)]
                elif evaluation_frequency == 2:  # Semestre
                    periods = [f"S{i+1}_{school_year}" for i in range(2)]
                elif evaluation_frequency == 3:  # Année
                    periods = [f"A_{school_year}"]

                # Associer à tous les élèves de l'établissement pour chaque période
                students = Student.objects.filter(associated_class__establishment_id=establishment_id)
                for student in students:
                    for period in periods:
                        StudentCompetency.objects.get_or_create(
                            student=student,
                            establishment_competency=ec,
                            period=period
                        )

                created.append({
                    "competence_id": ec.id,
                    "nom": ec.custom_name,
                    "state": "custom"
                })
            except Exception as e:
                errors.append({"error": str(e), "item": item})

        status_code = status.HTTP_201_CREATED if created else status.HTTP_400_BAD_REQUEST
        return JsonResponse({
            "created": created,
            "errors": errors
        }, status=status_code, safe=False)

    def delete(self, request):
        """
        Supprime une ou plusieurs compétences custom (EstablishmentCompetency) à partir d'une liste d'IDs.
        Supprime aussi les StudentCompetency associés.
        Attendu dans le body :
        {
            "ids": [1, 2, 3, ...]
        }
        """
        data = JSONParser().parse(request)
        ids = data.get("ids", [])
        deleted = []
        errors = []

        for ec_id in ids:
            try:
                ec = EstablishmentCompetency.objects.get(id=ec_id)
                # Supprimer les StudentCompetency associés
                StudentCompetency.objects.filter(establishment_competency=ec).delete()
                ec.delete()
                deleted.append(ec_id)
            except EstablishmentCompetency.DoesNotExist:
                errors.append({"id": ec_id, "error": "No object found"})

        return JsonResponse({
            "deleted": deleted,
            "errors": errors
        }, safe=False)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class EstablishmentCompetencyDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            ec = EstablishmentCompetency.objects.get(id=id)
            serializer = EstablishmentCompetencySerializer(ec)
            return JsonResponse(serializer.data, safe=False)
        except EstablishmentCompetency.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        try:
            ec = EstablishmentCompetency.objects.get(id=id)
        except EstablishmentCompetency.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        data = JSONParser().parse(request)
        serializer = EstablishmentCompetencySerializer(ec, data=data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, safe=False)
        return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        try:
            ec = EstablishmentCompetency.objects.get(id=id)
            ec.delete()
            return JsonResponse({'message': 'Deleted'}, safe=False)
        except EstablishmentCompetency.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)


# ===================== EVALUATIONS =====================

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class EvaluationListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        establishment_id = request.GET.get('establishment_id')
        school_class_id = request.GET.get('school_class')
        period = request.GET.get('period')
        
        if not establishment_id:
            return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)
        
        evaluations = Evaluation.objects.filter(establishment_id=establishment_id)
        
        if school_class_id:
            evaluations = evaluations.filter(school_class_id=school_class_id)
        if period:
            evaluations = evaluations.filter(period=period)
        
        serializer = EvaluationSerializer(evaluations, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        data = JSONParser().parse(request)
        serializer = EvaluationSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
        return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)


@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class EvaluationDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            evaluation = Evaluation.objects.get(id=id)
            serializer = EvaluationSerializer(evaluation)
            return JsonResponse(serializer.data, safe=False)
        except Evaluation.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        try:
            evaluation = Evaluation.objects.get(id=id)
        except Evaluation.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        data = JSONParser().parse(request)
        serializer = EvaluationSerializer(evaluation, data=data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, safe=False)
        return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        try:
            evaluation = Evaluation.objects.get(id=id)
            evaluation.delete()
            return JsonResponse({'message': 'Deleted'}, safe=False)
        except Evaluation.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)


# ===================== STUDENT EVALUATIONS =====================

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class StudentEvaluationListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        student_id = request.GET.get('student_id')
        evaluation_id = request.GET.get('evaluation_id')
        period = request.GET.get('period')
        school_class_id = request.GET.get('school_class_id')
        
        student_evals = StudentEvaluation.objects.all()
        
        if student_id:
            student_evals = student_evals.filter(student_id=student_id)
        if evaluation_id:
            student_evals = student_evals.filter(evaluation_id=evaluation_id)
        if period:
            student_evals = student_evals.filter(evaluation__period=period)
        if school_class_id:
            student_evals = student_evals.filter(evaluation__school_class_id=school_class_id)
        
        serializer = StudentEvaluationSerializer(student_evals, many=True)
        return JsonResponse(serializer.data, safe=False)


@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class StudentEvaluationBulkUpdateView(APIView):
    """
    Mise à jour en masse des notes des élèves pour une évaluation.
    Attendu dans le body :
    [
        { "student_id": 1, "evaluation_id": 1, "score": 15.5, "comment": "", "is_absent": false },
        ...
    ]
    """
    permission_classes = [IsAuthenticated]

    def put(self, request):
        data = JSONParser().parse(request)
        if not isinstance(data, list):
            data = [data]
        
        updated = []
        errors = []
        
        for item in data:
            student_id = item.get('student_id')
            evaluation_id = item.get('evaluation_id')
            
            if not student_id or not evaluation_id:
                errors.append({'error': 'student_id et evaluation_id sont requis', 'item': item})
                continue
            
            try:
                student_eval, created = StudentEvaluation.objects.update_or_create(
                    student_id=student_id,
                    evaluation_id=evaluation_id,
                    defaults={
                        'score': item.get('score'),
                        'comment': item.get('comment', ''),
                        'is_absent': item.get('is_absent', False)
                    }
                )
                updated.append(StudentEvaluationSerializer(student_eval).data)
            except Exception as e:
                errors.append({'error': str(e), 'item': item})
        
        return JsonResponse({'updated': updated, 'errors': errors}, safe=False)


@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class StudentEvaluationDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, id):
        try:
            student_eval = StudentEvaluation.objects.get(id=id)
            serializer = StudentEvaluationSerializer(student_eval)
            return JsonResponse(serializer.data, safe=False)
        except StudentEvaluation.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        try:
            student_eval = StudentEvaluation.objects.get(id=id)
        except StudentEvaluation.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        data = JSONParser().parse(request)
        serializer = StudentEvaluationSerializer(student_eval, data=data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, safe=False)
        return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, id):
        try:
            student_eval = StudentEvaluation.objects.get(id=id)
            student_eval.delete()
            return JsonResponse({'message': 'Deleted'}, safe=False)
        except StudentEvaluation.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
