import os
import mimetypes

from django.conf import settings
from django.http import FileResponse
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 (
    Domain,
    Category
)
from .serializers import (
    DomainSerializer,
    CategorySerializer
)

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

    def get(self, request):
        domains = Domain.objects.all()
        serializer = DomainSerializer(domains, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        data = JSONParser().parse(request)
        serializer = DomainSerializer(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 DomainDetailView(APIView):
    permission_classes = [IsAuthenticated]

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

    def put(self, request, id):
        try:
            domain = Domain.objects.get(id=id)
        except Domain.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        data = JSONParser().parse(request)
        serializer = DomainSerializer(domain, 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:
            domain = Domain.objects.get(id=id)
            domain.delete()
            return JsonResponse({'message': 'Deleted'}, safe=False)
        except Domain.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)

# Répète la même logique pour Category, Competency, EstablishmentCompetency

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

    def get(self, request):
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        data = JSONParser().parse(request)
        serializer = CategorySerializer(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 CategoryDetailView(APIView):
    permission_classes = [IsAuthenticated]

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

    def put(self, request, id):
        try:
            category = Category.objects.get(id=id)
        except Category.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
        data = JSONParser().parse(request)
        serializer = CategorySerializer(category, 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:
            category = Category.objects.get(id=id)
            category.delete()
            return JsonResponse({'message': 'Deleted'}, safe=False)
        except Category.DoesNotExist:
            return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)


class ServeFileView(APIView):
    """Sert les fichiers media de manière sécurisée avec authentification JWT."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        file_path = request.query_params.get('path', '')

        if not file_path:
            return JsonResponse(
                {'error': 'Le paramètre "path" est requis'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Nettoyer les prefixes media usuels si presents
        if file_path.startswith('/media/'):
            file_path = file_path[len('/media/'):]
        elif file_path.startswith('media/'):
            file_path = file_path[len('media/'):]

        # Nettoyer le préfixe /data/ si présent
        if file_path.startswith('/data/'):
            file_path = file_path[len('/data/'):]
        elif file_path.startswith('data/'):
            file_path = file_path[len('data/'):]

        # Construire le chemin absolu et le résoudre pour éliminer les traversals
        absolute_path = os.path.realpath(
            os.path.join(settings.MEDIA_ROOT, file_path)
        )

        # Protection contre le path traversal
        media_root = os.path.realpath(settings.MEDIA_ROOT)
        if not absolute_path.startswith(media_root + os.sep) and absolute_path != media_root:
            return JsonResponse(
                {'error': 'Accès non autorisé'},
                status=status.HTTP_403_FORBIDDEN,
            )

        if not os.path.isfile(absolute_path):
            return JsonResponse(
                {'error': 'Fichier introuvable'},
                status=status.HTTP_404_NOT_FOUND,
            )

        content_type, _ = mimetypes.guess_type(absolute_path)
        if content_type is None:
            content_type = 'application/octet-stream'

        response = FileResponse(
            open(absolute_path, 'rb'),
            content_type=content_type,
        )
        response['Content-Disposition'] = (
            f'inline; filename="{os.path.basename(absolute_path)}"'
        )
        return response
