from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import NotFound
from django.core.mail import send_mail
import random
import uuid
from django.core.cache import cache
from .models import User
from .serializers import UserSerializer, UserSpecialSerializer, GenericUserSerializer, UserAuthentificationSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.tokens import RefreshToken
import re
from config.authentication import (
    IsAuthenticatedAndOwner, 
    IsAuthenticatedOrEmailVerified, 
    JWTAuthenticationWithUserCheck,
    IsAuthenticatedOrCreateOnly
)
from course.models import Course
from utils.create_course import copy_course

class UserView(APIView):
    authentication_classes = [JWTAuthenticationWithUserCheck]
    permission_classes = [IsAuthenticatedAndOwner]
    
    @staticmethod
    def get_object(pid):
        try:
            return User.objects.get(publicIdentifier=pid)
        except User.DoesNotExist:
            raise NotFound({"error": "User not found"})

    def get(self, request, pid):
        user = self.get_object(request.user.publicIdentifier)
        self.check_object_permissions(request, user)
        serializer = UserSerializer(user)
        return Response(serializer.data)

    def put(self, request, pid):
        user = self.get_object(request.user.publicIdentifier)
        self.check_object_permissions(request, user)
        serializer = UserSerializer(user, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pid):
        user = self.get_object(request.user.publicIdentifier)
        self.check_object_permissions(request, user)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class GenericUserView(APIView):

    def verify_email_code(self, request):
        try:
            email, code = cache.get(request.data.get('codeID'))
            return code == request.data.get('code') and email == request.data.get('email')
        except:
            return False

    @staticmethod
    def password_is_valid(request, user):
        try:
            password = request.data.get('password')
            return user.check_password(password)
        except:
            return False
    
    def get(self, request):
        email = request.query_params.get('email')
        if not email: 
            return Response({"error": "You must send an email in query"}, status=status.HTTP_400_BAD_REQUEST)
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND)
        else:
            serializer = GenericUserSerializer(user)
            return Response(serializer.data)
    
    def put(self, request):
        if not self.verify_email_code(request):
            return Response({"error": "Invalid code or email"}, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            pid = request.data.get('publicIdentifier')
            user = UserView.get_object(pid)
            password = request.data.get('newPassword')
            if password and len(password) < 127:
                user.set_password(password)
            serializer = UserSpecialSerializer(user, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        except TypeError:
            return Response({"error": "invalid request"}, status=status.HTTP_400_BAD_REQUEST)
    
    def post(self, request):
        if not self.verify_email_code(request):
            return Response({"error": "Invalid code or email", "code": "invalid_code_or_email"}, status=status.HTTP_404_NOT_FOUND)

        data = request.data
        serializer = UserSpecialSerializer(data=data)
        if serializer.is_valid():
            user = serializer.save()
            
            # Générer les tokens
            refresh = RefreshToken.for_user(user)
            access = refresh.access_token
            tokens = {
                'refresh': str(refresh),
                'access': str(access)
            }
            return Response({
                "user": serializer.data,
                "tokens": tokens
            })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class UserAuthentificationView(TokenObtainPairView):
    permission_classes = [IsAuthenticatedOrEmailVerified]
    
    def post(self, request, *args, **kwargs):
        try:
            email = request.data.get('email')
            user = User.objects.get(email=email)
            
            if not GenericUserView.password_is_valid(request, user):
                return Response({"error": "Identifiants invalides"}, status=status.HTTP_401_UNAUTHORIZED)
                
            serializer = UserSerializer(user)
            tokens = super().post(request, *args, **kwargs)
            response = {"user": serializer.data, "tokens": tokens.data}
            return Response(response, status=status.HTTP_202_ACCEPTED)
            
        except User.DoesNotExist:
            return Response({"error": "Email inconnu"}, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            print(e)
            return Response({"error": "Une erreur est survenue"}, status=status.HTTP_400_BAD_REQUEST)


class ManagePassword(APIView):
    
    def send_email(self, to_email, subject, message):
        return send_mail(
            subject,
            message,
            'admin@ed-disce.fr',
            [to_email],
            fail_silently=False
        )
        
    def post(self, request):
        email = request.data.get('email')

        if not email:
            return Response({"error": "Email requis"}, status=status.HTTP_400_BAD_REQUEST)

        email_regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(email_regex, email):
            return Response({"error": "Format d'email invalide"}, status=status.HTTP_400_BAD_REQUEST)
            
        code = ''.join([str(random.randint(0, 9)) for _ in range(6)])
        codeID = str(uuid.uuid4())
        cache.set(codeID, [email, code], timeout=600)
        
        subject = "Votre code de validation " + code
        message = "Votre code de validation ED&DISCE est le " + code + ". Entrez ce code dans l'onglet qui vient de s'ouvrir dans votre fenêtre de connexion. Ce code est valable 10 minutes."
        
        if self.send_email(email, subject, message):
            return Response({'codeID': codeID}, status=status.HTTP_200_OK)
        return Response({"message": "Échec de l'envoi du code"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

