from django.http.response import JsonResponse
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer
from Subscriptions.models import (
    RegistrationForm,
    RegistrationSchoolFileMaster,
    RegistrationSchoolFileTemplate
)
from N3wtSchool import bdd
import logging
import Subscriptions.util as util

logger = logging.getLogger(__name__)

class RegistrationSchoolFileMasterView(APIView):
    parser_classes = [MultiPartParser, FormParser, JSONParser]

    @swagger_auto_schema(
        operation_description="Récupère tous les masters de templates d'inscription pour un établissement donné",
        manual_parameters=[
            openapi.Parameter(
                'establishment_id',
                openapi.IN_QUERY,
                description="ID de l'établissement",
                type=openapi.TYPE_INTEGER,
                required=True
            )
        ],
        responses={200: RegistrationSchoolFileMasterSerializer(many=True)}
    )
    def get(self, request):
        establishment_id = request.GET.get('establishment_id')
        if not establishment_id:
            return Response({'error': "Paramètre 'establishment_id' requis"}, status=status.HTTP_400_BAD_REQUEST)

        # Filtrer les masters liés à l'établissement via groups.establishment
        masters = RegistrationSchoolFileMaster.objects.filter(
            groups__establishment__id=establishment_id
        ).distinct()
        serializer = RegistrationSchoolFileMasterSerializer(masters, many=True)
        return Response(serializer.data)

    @swagger_auto_schema(
        operation_description="Crée un nouveau master de template d'inscription",
        request_body=RegistrationSchoolFileMasterSerializer,
        responses={
            201: RegistrationSchoolFileMasterSerializer,
            400: "Données invalides"
        }
    )
    def post(self, request):
        logger.info(f"raw request.data: {request.data}")

        payload, resp = util.build_payload_from_request(request)
        if resp:
            return resp


        logger.info(f"payload for serializer: {payload}")
        serializer = RegistrationSchoolFileMasterSerializer(data=payload, partial=True)
        if serializer.is_valid():
            obj = serializer.save()

            # Propager la création des templates côté serveur pour les RegistrationForm
            try:
                groups_qs = obj.groups.all()
                if groups_qs.exists():
                    # Tous les RegistrationForm dont fileGroup est dans les groups du master
                    rfs = RegistrationForm.objects.filter(fileGroup__in=groups_qs).distinct()
                    for rf in rfs:
                        try:
                            util.create_templates_for_registration_form(rf)
                        except Exception as e:
                            logger.exception("Error creating templates for RF %s from master %s: %s", getattr(rf, 'pk', None), getattr(obj, 'pk', None), e)
            except Exception:
                logger.exception("Error while propagating templates after master creation %s", getattr(obj, 'pk', None))


            return Response(RegistrationSchoolFileMasterSerializer(obj).data, status=status.HTTP_201_CREATED)

        logger.error(f"serializer errors: {serializer.errors}")
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class RegistrationSchoolFileMasterSimpleView(APIView):
    parser_classes = [MultiPartParser, FormParser, JSONParser]
    @swagger_auto_schema(
        operation_description="Récupère un master de template d'inscription spécifique",
        responses={
            200: RegistrationSchoolFileMasterSerializer,
            404: "Master non trouvé"
        }
    )
    def get(self, request, id):
        master = bdd.getObject(_objectName=RegistrationSchoolFileMaster, _columnName='id', _value=id)
        if master is None:
            return JsonResponse({"errorMessage":'Le master de template n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
        serializer = RegistrationSchoolFileMasterSerializer(master)
        return JsonResponse(serializer.data, safe=False)

    @swagger_auto_schema(
        operation_description="Met à jour un master de template d'inscription existant",
        request_body=RegistrationSchoolFileMasterSerializer,
        responses={
            200: RegistrationSchoolFileMasterSerializer,
            400: "Données invalides",
            404: "Master non trouvé"
        }
    )
    def put(self, request, id):
        master = bdd.getObject(_objectName=RegistrationSchoolFileMaster, _columnName='id', _value=id)
        if master is None:
            return JsonResponse({'erreur': "Le master de template n'a pas été trouvé"}, safe=False, status=status.HTTP_404_NOT_FOUND)

        # snapshot des groups avant update
        old_group_ids = set(master.groups.values_list('id', flat=True))

        # Normaliser payload (supporte form-data avec champ 'data' JSON ou fichier JSON)
        payload, resp = util.build_payload_from_request(request)
        if resp:
            return resp

        # Garde-fou: eviter d'ecraser un master dynamique existant avec un
        # formMasterData vide/malforme (cas observe en multipart).
        if 'formMasterData' in payload:
            incoming_form_data = payload.get('formMasterData')
            current_is_dynamic = (
                isinstance(master.formMasterData, dict)
                and bool(master.formMasterData.get('fields'))
            )
            incoming_is_dynamic = (
                isinstance(incoming_form_data, dict)
                and bool(incoming_form_data.get('fields'))
            )
            if current_is_dynamic and not incoming_is_dynamic:
                logger.warning(
                    "formMasterData invalide recu pour master %s: conservation de la config dynamique existante",
                    master.pk,
                )
                payload['formMasterData'] = master.formMasterData


        logger.info(f"payload for update serializer: {payload}")
        serializer = RegistrationSchoolFileMasterSerializer(master, data=payload, partial=True)
        if serializer.is_valid():
            obj = serializer.save()

            # groups après update
            new_group_ids = set(obj.groups.values_list('id', flat=True))

            removed_group_ids = old_group_ids - new_group_ids
            added_group_ids = new_group_ids - old_group_ids

            # Pour chaque RF appartenant aux groupes retirés -> nettoyer les templates (idempotent)
            if removed_group_ids:
                logger.info("REMOVE IDs")
                try:
                    rfs_removed = RegistrationForm.objects.filter(fileGroup__in=list(removed_group_ids)).distinct()
                    for rf in rfs_removed:
                        try:
                            util.create_templates_for_registration_form(rf)  # supprimera les templates obsolètes
                        except Exception as e:
                            logger.exception("Error cleaning templates for RF %s after master %s group removal: %s", getattr(rf, 'pk', None), getattr(obj, 'pk', None), e)
                except Exception:
                    logger.exception("Error while processing RFs for removed groups after master update %s", getattr(obj, 'pk', None))

            # Pour chaque RF appartenant aux groupes ajoutés -> créer les templates manquants
            if added_group_ids:
                logger.info("ADD IDs")
                try:
                    rfs_added = RegistrationForm.objects.filter(fileGroup__in=list(added_group_ids)).distinct()
                    for rf in rfs_added:
                        try:
                            util.create_templates_for_registration_form(rf)  # créera les templates manquants
                        except Exception as e:
                            logger.exception("Error creating templates for RF %s after master %s group addition: %s", getattr(rf, 'pk', None), getattr(obj, 'pk', None), e)
                except Exception:
                    logger.exception("Error while processing RFs for added groups after master update %s", getattr(obj, 'pk', None))

            return Response(serializer.data, status=status.HTTP_200_OK)

        logger.error(f"serializer errors on put: {serializer.errors}")
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @swagger_auto_schema(
        operation_description="Supprime un master de template d'inscription",
        responses={
            204: "Suppression réussie",
            404: "Master non trouvé"
        }
    )
    def delete(self, request, id):
        master = bdd.getObject(_objectName=RegistrationSchoolFileMaster, _columnName='id', _value=id)
        if master is not None:
            # Supprimer tous les templates liés et leurs fichiers PDF
            templates = RegistrationSchoolFileTemplate.objects.filter(master=master)
            for template in templates:
                if template.file and template.file.name:
                    template.file.delete(save=False)
                template.delete()
            master.delete()
            return JsonResponse({'message': 'La suppression du master de template et des fichiers associés a été effectuée avec succès'}, safe=False, status=status.HTTP_200_OK)
        else:
            return JsonResponse({'erreur': 'Le master de template n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
