from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.permissions import IsAuthenticated
from .serializers import ExerciseSerializer, ExerciseListSerializer
from .models import Exercise
import requests
import json
from config.authentication import JWTAuthenticationWithUserCheck, IsAuthenticatedAndOwner
from utils.stringifiers import markdownToQuilldelta

class ExerciseListView(APIView):
    authentication_classes = [JWTAuthenticationWithUserCheck]
    permission_classes = [IsAuthenticatedAndOwner]

    def get(self, request):
        exercises = Exercise.objects.filter(user=request.user.publicIdentifier)
        serializer = ExerciseListSerializer(exercises, many=True)
        return Response(serializer.data)

    def post(self, request):
        data = request.data
        data['user'] = str(request.user.publicIdentifier)
        serializer = ExerciseSerializer(data=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 ExerciseDetailView(APIView):
    authentication_classes = [JWTAuthenticationWithUserCheck]
    permission_classes = [IsAuthenticatedAndOwner]

    @staticmethod
    def get_object(pid, request):
        try:
            return Exercise.objects.get(publicIdentifier=pid, user=request.user.publicIdentifier)
        except Exercise.DoesNotExist:
            raise Http404

    def get(self, request, pid):
        exercise = self.get_object(pid, request) # c'est une instance de la classe Flashcard
        serializer = ExerciseSerializer(exercise) # c'est une instance du serializer, dont l'attribut data contient un dictionnaire python
        return Response(serializer.data)

    def put(self, request, pid):
        exercise = self.get_object(pid, request) # On récupère la flashcard à modifier
        serializer = ExerciseSerializer(exercise, data=request.data) # On remplace avec les nouvelles données
        if serializer.is_valid():
            serializer.save() # Si tout est valide, on sauvegarde les nouvelles données
            return Response(serializer.data)
        return Response(serializer.errors,
                        status=status.HTTP_400_BAD_REQUEST) # Sinon, on ne sauvegarde pas et on renvoit une erreur

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


class CorrectExercise(APIView):
    def post(self, request):
        exercise = ExerciseDetailView.get_object(request.data.get('publicIdentifier'), request)
        userResponse = request.data.get('userResponse')
        api_key = "H20rSMbOuAzRkkuUTUS64tfTjyzfPDRb"
        url = "https://api.mistral.ai/v1/chat/completions"
        headers = {
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json',
        }
        exerciseCorrection = ""
        if exercise.correctAnswer != "":
            exerciseCorrection = "Voici une correction de cet exercice : " + exercise.correctAnswer
        personalizedPrompt = "Tu va recevoir une réponse proposé par un apprenant. Compare cette réponse à la correction de l'exercice et rédige un texte à destination de l'apprenant, qui fait ressortir les points de différence avec la correction."
        if(exercise.academicLevel != '' and exercise.subjectStudied != ''):
            personalizedPrompt += "L'apprenant étudie le sujet : " + exercise.subjectStudied + " au niveau : " + exercise.academicLevel
        body = {
            "model": "mistral-small-latest",
            "messages": [
                {
                    "role": "system",
                    "content": "Voici une consigne d'exercice : " + json.dumps(exercise.instructions) + ". " + exerciseCorrection
                },
                {
                    "role": "system",
                    "content": personalizedPrompt
                },
                {
                    "role": "system",
                    "content": "Renvoie une réponse de moins de 200 caractères, au format JSON, avec la clé 'correction', et la clé 'masteryLevel'. La clé masteryLevel contiendra une valeur parmi 'perfect', 'correct', 'false', ou 'incomplete', correspondant à la qualité de la réponse de l'élève. " + 
                    "Tu dois donc renvoyer un objet ayant la structure suivante : {'correction': 'ta_correction', 'masteryLevel': 'niveau_de_la_reponse_proposé'}" +
                    "Rédige la réponse comme si tu parlais directement à l'apprenant. Vouvoie-le"
                },
                {
                    "role": "user",
                    "content": "Voici la réponse de l'apprenant : " + json.dumps(userResponse)
                }
            ],
            "response_format": {"type": "json_object"},
            "temperature": 0.7,
            "top_p": 1,
            "max_tokens": 511,
            "stream": False,
            "safe_prompt": False,
            "random_seed": 1337
        }
        response = requests.post(url, headers=headers, json=body) # envoi de la requête à l'API
        if response.status_code == 200:
            APIresponse = json.loads(response.json()['choices'][0]['message']['content'])
            return Response(APIresponse, status=status.HTTP_200_OK)
            # Contient normalement un champ 'correction' et un champ 'level'
        else:
            return Response({'error': response.text}, status=response.status_code)


# Lorsque l'utilisateur réussi un exercice, l'exercice est marqué comme réussi
# C'est l'utilisateur qui clique sur un bouton pour dire "Je maitrise cet exercice" ou "Revoir cet exercice plus tard"
# Si l'utilisateur maitrise tout les exercices qui sont proposés, on lui affiche un bouton lui proposant de générer un nouvel exercice
# (A rapidement changer par quelque chose d'autre : je voudrais pouvoir suivre ce que font les gens, et leur proposer l'exercice le plus approprié étant donné leur niveau)
# Il suffirait d'avoir un niveau de difficultée pour l'exercice, d'associer chaque exercice à une notion (les flashcards) et de considérer le niveau de maitrise d'un cours par notion. 
# Lorsque l'utilisateur maitrise au niveau 1 une notion, le prochain exercice généré sera de niveau 2, ect...
