from django.http.response import JsonResponse
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
import os
import glob

from Subscriptions.serializers import RegistrationSchoolFileTemplateSerializer
from Subscriptions.models import RegistrationSchoolFileTemplate
from N3wtSchool import bdd
import logging
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
import Subscriptions.util as util

logger = logging.getLogger(__name__)


def _extract_nested_responses(data, max_depth=8):
    """Extrait le dictionnaire de reponses depuis des structures imbriquees."""
    current = data
    for _ in range(max_depth):
        if not isinstance(current, dict):
            return None
        nested = current.get("responses")
        if isinstance(nested, dict):
            current = nested
            continue
        return current
    return current if isinstance(current, dict) else None

class RegistrationSchoolFileTemplateView(APIView):
    @swagger_auto_schema(
        operation_description="Récupère tous les 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: RegistrationSchoolFileTemplateSerializer(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 templates liés à l'établissement via master.groups.establishment
        templates = RegistrationSchoolFileTemplate.objects.filter(
            master__groups__establishment__id=establishment_id
        ).distinct()
        serializer = RegistrationSchoolFileTemplateSerializer(templates, many=True)
        return Response(serializer.data)

    @swagger_auto_schema(
        operation_description="Crée un nouveau template d'inscription",
        request_body=RegistrationSchoolFileTemplateSerializer,
        responses={
            201: RegistrationSchoolFileTemplateSerializer,
            400: "Données invalides"
        }
    )
    def post(self, request):
        serializer = RegistrationSchoolFileTemplateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

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

    @swagger_auto_schema(
        operation_description="Récupère un template d'inscription spécifique",
        responses={
            200: RegistrationSchoolFileTemplateSerializer,
            404: "Template non trouvé"
        }
    )
    def get(self, request, id):
        template = bdd.getObject(_objectName=RegistrationSchoolFileTemplate, _columnName='id', _value=id)
        if template is None:
            return JsonResponse({"errorMessage":'Le template d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
        serializer = RegistrationSchoolFileTemplateSerializer(template)
        return JsonResponse(serializer.data, safe=False)

    @swagger_auto_schema(
        operation_description="Met à jour un template d'inscription existant",
        request_body=RegistrationSchoolFileTemplateSerializer,
        responses={
            200: RegistrationSchoolFileTemplateSerializer,
            400: "Données invalides",
            404: "Template non trouvé"
        }
    )
    def put(self, request, id):
        # Normaliser la payload (support form-data avec champ 'data' JSON ou fichier JSON)
        payload, resp = util.build_payload_from_request(request)
        if resp is not None:
            return resp

        # Synchroniser fields[].value dans le payload AVANT le serializer (pour les formulaires dynamiques)
        formTemplateData = payload.get('formTemplateData')
        if formTemplateData and isinstance(formTemplateData, dict):
            responses = None
            if "responses" in formTemplateData:
                resp = formTemplateData["responses"]
                responses = _extract_nested_responses(resp)

            # Nettoyer les meta-cles qui ne sont pas des reponses de champs
            if isinstance(responses, dict):
                cleaned = {
                    key: value
                    for key, value in responses.items()
                    if key not in {"responses", "formId", "id", "templateId"}
                }
                responses = cleaned

            if responses and "fields" in formTemplateData:
                for field in formTemplateData["fields"]:
                    field_id = field.get("id")
                    if field_id and field_id in responses:
                        field["value"] = responses[field_id]

            # Stocker les reponses aplaties pour eviter l'empilement responses.responses
            if isinstance(responses, dict):
                formTemplateData["responses"] = responses
            payload['formTemplateData'] = formTemplateData

        template = bdd.getObject(_objectName=RegistrationSchoolFileTemplate, _columnName='id', _value=id)
        if template is None:
            return JsonResponse({'erreur': 'Le template d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)

        # Cas 1 : Upload d'un fichier existant (PDF/image)
        if 'file' in request.FILES:
            upload = request.FILES['file']
            file_field = template.file
            upload_name = upload.name
            upload_dir = os.path.dirname(file_field.path) if file_field and file_field.name else None
            if upload_dir:
                base_name, _ = os.path.splitext(upload_name)
                pattern = os.path.join(upload_dir, f"{base_name}.*")
                for f in glob.glob(pattern):
                    try:
                        if os.path.exists(f):
                            os.remove(f)
                            logger.info(f"Suppression du fichier existant (pattern): {f}")
                    except Exception as e:
                        logger.error(f"Erreur suppression fichier existant (pattern): {e}")
                target_path = os.path.join(upload_dir, upload_name)
                if os.path.exists(target_path):
                    try:
                        os.remove(target_path)
                    except Exception as e:
                        logger.error(f"Erreur suppression fichier cible: {e}")
            # On écrase le fichier existant sans passer par le serializer
            template.file.save(upload_name, upload, save=True)
            return Response({'message': 'Template mis à jour avec succès', 'data': RegistrationSchoolFileTemplateSerializer(template).data}, status=status.HTTP_200_OK)

        # Cas 2 : Formulaire dynamique (JSON)
        serializer = RegistrationSchoolFileTemplateSerializer(template, data=payload, partial=True)
        if serializer.is_valid():
            serializer.save()
            # Régénérer le PDF si besoin
            formTemplateData = serializer.validated_data.get('formTemplateData')
            if (
                formTemplateData
                and isinstance(formTemplateData, dict)
                and formTemplateData.get("fields")
                and hasattr(template, "file")
            ):
                # Lire le contenu du fichier source en mémoire AVANT suppression.
                # Priorité au fichier master (document source admin) pour éviter
                # de re-générer à partir d'un PDF template déjà enrichi.
                base_pdf_content = None
                base_file_ext = None
                if template.master and template.master.file and template.master.file.name:
                    base_file_ext = os.path.splitext(template.master.file.name)[1].lower()
                    try:
                        template.master.file.open('rb')
                        base_pdf_content = template.master.file.read()
                        template.master.file.close()
                    except Exception as e:
                        logger.error(f"Erreur lecture fichier source master: {e}")
                elif template.file and template.file.name:
                    base_file_ext = os.path.splitext(template.file.name)[1].lower()
                    try:
                        template.file.open('rb')
                        base_pdf_content = template.file.read()
                        template.file.close()
                    except Exception as e:
                        logger.error(f"Erreur lecture fichier source template: {e}")
                    try:
                        old_path = template.file.path
                        template.file.delete(save=False)
                        if os.path.exists(old_path):
                            os.remove(old_path)
                    except Exception as e:
                        logger.error(f"Erreur lors de la suppression du fichier existant: {e}")
                from Subscriptions.util import generate_form_json_pdf
                pdf_file = generate_form_json_pdf(
                    template.registration_form,
                    formTemplateData,
                    base_pdf_content=base_pdf_content,
                    base_file_ext=base_file_ext,
                )
                form_name = (formTemplateData.get("title") or template.name or f"formulaire_{template.id}").strip().replace(" ", "_")
                pdf_filename = f"{form_name}.pdf"
                util.save_file_field_without_suffix(
                    template,
                    'file',
                    pdf_filename,
                    pdf_file,
                    save=True,
                )
            return Response({'message': 'Template mis à jour avec succès', 'data': serializer.data}, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @swagger_auto_schema(
        operation_description="Supprime un template d'inscription",
        responses={
            204: "Suppression réussie",
            404: "Template non trouvé"
        }
    )
    def delete(self, request, id):
        template = bdd.getObject(_objectName=RegistrationSchoolFileTemplate, _columnName='id', _value=id)
        if template is not None:
            # Suppression du fichier PDF associé
            if template.file and template.file.name:
                file_path = template.file.path
                template.file.delete(save=False)
                # Vérification post-suppression
                if os.path.exists(file_path):
                    try:
                        os.remove(file_path)
                        logger.info(f"Fichier supprimé manuellement: {file_path}")
                    except Exception as e:
                        logger.error(f"Erreur lors de la suppression manuelle du fichier: {e}")
            template.delete()
            return JsonResponse({'message': 'La suppression du template a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT)
        else:
            return JsonResponse({'erreur': 'Le template n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
