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, MultiPartParser, FormParser
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.permissions import IsAuthenticated, BasePermission
from .models import Establishment
from .serializers import EstablishmentSerializer
from N3wtSchool.bdd import delete_object, getAllObjects, getObject
from School.models import EstablishmentCompetency, Competency
from django.db.models import Q
from Auth.models import Profile, ProfileRole, Directeur
from Settings.models import SMTPSettings
import N3wtSchool.mailManager as mailer
import os
from N3wtSchool import settings


class IsWebhookApiKey(BasePermission):
    def has_permission(self, request, view):
        api_key = settings.WEBHOOK_API_KEY
        if not api_key:
            return False
        return request.headers.get('X-API-Key') == api_key


class IsAuthenticatedOrWebhookApiKey(BasePermission):
    def has_permission(self, request, view):
        if request.user and request.user.is_authenticated:
            return True
        return IsWebhookApiKey().has_permission(request, view)


class EstablishmentListCreateView(APIView):

    def get_permissions(self):
        if self.request.method == 'POST':
            return [IsAuthenticatedOrWebhookApiKey()]
        return [IsAuthenticated()]

    def get(self, request):
        establishments = getAllObjects(Establishment)
        establishments_serializer = EstablishmentSerializer(establishments, many=True)
        return JsonResponse(establishments_serializer.data, safe=False, status=status.HTTP_200_OK)

    def post(self, request):
        establishment_data = JSONParser().parse(request)
        try:
            establishment, data = create_establishment_with_directeur(establishment_data)
            # Création des EstablishmentCompetency pour chaque compétence existante
            competencies = Competency.objects.filter(
                Q(end_of_cycle=True) | ~Q(level=None)
            )
            for competency in competencies:
                EstablishmentCompetency.objects.get_or_create(
                    establishment=establishment,
                    competency=competency,
                    defaults={'is_required': True}
                )
            return JsonResponse(data, safe=False, status=status.HTTP_201_CREATED)
        except Exception as e:
            return JsonResponse({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class EstablishmentDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]

    def get(self, request, id=None):
        try:
            establishment = Establishment.objects.get(id=id)
            establishment_serializer = EstablishmentSerializer(establishment)
            return JsonResponse(establishment_serializer.data, safe=False)
        except Establishment.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

    def put(self, request, id):
        """
        Met à jour un établissement existant.
        Accepte les données en multipart/form-data pour permettre l'upload de fichiers (ex : logo).
        """
        try:
            establishment = Establishment.objects.get(id=id)
        except Establishment.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

        # Utilise request.data pour supporter multipart/form-data (fichiers et champs classiques)
        establishment_serializer = EstablishmentSerializer(establishment, data=request.data, partial=True)
        if establishment_serializer.is_valid():
            establishment_serializer.save()
            return JsonResponse(establishment_serializer.data, safe=False, status=status.HTTP_200_OK)
        return JsonResponse(establishment_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)

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

def create_establishment_with_directeur(establishment_data):
    # Extraction des sous-objets
    # school_name = establishment_data.get("name")
    directeur_data = establishment_data.pop("directeur", None)
    smtp_settings_data = establishment_data.pop("smtp_settings", {})

    # Vérification de la présence du directeur
    if not directeur_data or not directeur_data.get("email"):
        raise ValueError("Le champ 'directeur.email' est obligatoire.")

    directeur_email = directeur_data.get("email")
    last_name = directeur_data.get("last_name", "")
    first_name = directeur_data.get("first_name", "")
    password = directeur_data.get("password")
    if not password:
        raise ValueError("Le champ 'directeur.password' est obligatoire pour créer un établissement.")

    # Création ou récupération du profil utilisateur
    profile, created = Profile.objects.get_or_create(
        email=directeur_email,
        defaults={"username": directeur_email}
    )
    if created or not profile.has_usable_password():
        profile.set_password(password)
        profile.save()

    # Création de l'établissement
    establishment_serializer = EstablishmentSerializer(data=establishment_data)
    establishment_serializer.is_valid(raise_exception=True)
    # base_dir = os.path.join(settings.MEDIA_ROOT, f"logo/school_{school_name}")
    # os.makedirs(base_dir, exist_ok=True)
    establishment = establishment_serializer.save()

    # Création ou récupération du ProfileRole ADMIN pour ce profil et cet établissement
    profile_role, _ = ProfileRole.objects.get_or_create(
        profile=profile,
        establishment=establishment,
        role_type=ProfileRole.RoleType.PROFIL_ADMIN,
        defaults={"is_active": False}
    )

    # Création ou mise à jour du Directeur lié à ce ProfileRole
    Directeur.objects.update_or_create(
        profile_role=profile_role,
        defaults={
            "last_name": last_name,
            "first_name": first_name
        }
    )

    # Création du SMTPSettings rattaché à l'établissement si des données sont fournies
    if smtp_settings_data:
        smtp_settings_data["establishment"] = establishment
        SMTPSettings.objects.create(**smtp_settings_data)

    # Envoi du mail
    mailer.sendRegistrationDirector(directeur_email, establishment.pk)
    return establishment, establishment_serializer.data