from django.shortcuts import get_object_or_404
from django.contrib.auth import get_user_model
from rest_framework import status, permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import PermissionDenied

from .models import MentoringThread, MentoringMessage, AdminMentorThread, AdminMentorMessage
from .serializers import (
    MentoringThreadSerializer,
    MentoringThreadListSerializer,
    MentoringMessageSerializer,
    AdminMentorThreadSerializer,
    AdminMentorThreadListSerializer,
    AdminMentorMessageSerializer,
)

User = get_user_model()


def _is_mentor(user):
    return getattr(user, 'role', None) == 'MENTOR'


def _is_admin_or_mentor(user):
    return getattr(user, 'is_staff', False) or _is_mentor(user)


class IsAdminOrMentor(permissions.BasePermission):
    """Admin ou utilisateur avec role=MENTOR."""
    def has_permission(self, request, view):
        return request.user.is_authenticated and _is_admin_or_mentor(request.user)


def _student_can_reply(thread):
    """True si le dernier message du mentor a student_can_reply=True."""
    last_mentor = thread.messages.filter(is_from_mentor=True).order_by('-created_at').first()
    return last_mentor is not None and last_mentor.student_can_reply


# --- ÉTUDIANT : obtenir ou créer le fil, lister les messages, envoyer un message ---
class StudentThreadView(APIView):
    """GET : récupère le fil pour document_type (créé si besoin). POST non utilisé pour le fil."""
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, document_type):
        if document_type not in dict(MentoringThread.DOC_TYPE_CHOICES):
            return Response({"error": "Type de document invalide."}, status=status.HTTP_400_BAD_REQUEST)
        thread, _ = MentoringThread.objects.get_or_create(
            student=request.user,
            document_type=document_type,
            defaults={'status': 'in_progress'},
        )
        serializer = MentoringThreadSerializer(thread)
        data = serializer.data
        data['student_can_reply'] = _student_can_reply(thread)
        return Response(data)


class StudentMessageCreateView(APIView):
    """POST : l'étudiant envoie un message (autorisé seulement si le mentor a mis student_can_reply sur son dernier message)."""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, thread_id):
        thread = get_object_or_404(MentoringThread, id=thread_id, student=request.user)
        if not _student_can_reply(thread):
            return Response(
                {"error": "Vous ne pouvez pas répondre pour le moment. Le mentor doit vous autoriser à répondre."},
                status=status.HTTP_403_FORBIDDEN,
            )
        content = (request.data.get("content") or "").strip()
        if not content:
            return Response({"error": "Le message ne peut pas être vide."}, status=status.HTTP_400_BAD_REQUEST)
        msg = MentoringMessage.objects.create(
            thread=thread,
            sender=request.user,
            content=content,
            is_from_mentor=False,
            student_can_reply=False,
        )
        return Response(MentoringMessageSerializer(msg).data, status=status.HTTP_201_CREATED)


# --- ADMIN / MENTOR : lister les fils, détail + messages, envoyer message, noter, autoriser réponse ---
class AdminThreadListView(APIView):
    """GET : liste des fils (optionnel ?user_id= pour filtrer par étudiant). Admin : tous. Mentor : uniquement ses étudiants."""
    permission_classes = [IsAdminOrMentor]

    def get(self, request):
        qs = MentoringThread.objects.all().select_related('student', 'mentor')
        if _is_mentor(request.user) and not getattr(request.user, 'is_staff', False):
            qs = qs.filter(student__mentor=request.user)
        user_id = request.query_params.get('user_id')
        if user_id:
            qs = qs.filter(student_id=user_id)
        serializer = MentoringThreadListSerializer(qs, many=True)
        return Response(serializer.data)


class AdminThreadDetailView(APIView):
    """GET : détail du fil + messages. PATCH : grade, status. POST : créer un message (mentor)."""
    permission_classes = [IsAdminOrMentor]

    def _get_thread(self, request, thread_id):
        thread = get_object_or_404(MentoringThread, id=thread_id)
        if _is_mentor(request.user) and not getattr(request.user, 'is_staff', False):
            if thread.student.mentor_id != request.user.id:
                raise PermissionDenied("Vous n'êtes pas le mentor assigné de cet étudiant.")
        return thread

    def get(self, request, thread_id):
        thread = self._get_thread(request, thread_id)
        serializer = MentoringThreadSerializer(thread)
        return Response(serializer.data)

    def patch(self, request, thread_id):
        thread = self._get_thread(request, thread_id)
        for field in ('grade', 'status'):
            if field in request.data:
                setattr(thread, field, request.data[field])
        if not thread.mentor_id:
            thread.mentor = request.user
        thread.save()
        return Response(MentoringThreadSerializer(thread).data)

    def post(self, request, thread_id):
        """Mentor envoie un message. Body: content, student_can_reply (bool). L'admin ne peut pas participer (lecture seule)."""
        thread = self._get_thread(request, thread_id)
        if getattr(request.user, 'is_staff', False) and not _is_mentor(request.user):
            raise PermissionDenied("L'administrateur peut uniquement consulter les discussions mentor-étudiant, pas y envoyer de messages.")
        content = (request.data.get("content") or "").strip()
        if not content:
            return Response({"error": "Le message ne peut pas être vide."}, status=status.HTTP_400_BAD_REQUEST)
        student_can_reply = request.data.get("student_can_reply", False)
        if not thread.mentor_id:
            thread.mentor = request.user
            thread.save(update_fields=['mentor'])
        msg = MentoringMessage.objects.create(
            thread=thread,
            sender=request.user,
            content=content,
            is_from_mentor=True,
            student_can_reply=bool(student_can_reply),
        )
        return Response(MentoringMessageSerializer(msg).data, status=status.HTTP_201_CREATED)


class AdminGetOrCreateThreadView(APIView):
    """GET ou créer le fil pour un étudiant et un type de document. Admin : tout user. Mentor : uniquement ses étudiants."""
    permission_classes = [IsAdminOrMentor]

    def get(self, request, user_id, document_type):
        if document_type not in dict(MentoringThread.DOC_TYPE_CHOICES):
            return Response({"error": "Type de document invalide."}, status=status.HTTP_400_BAD_REQUEST)
        student = get_object_or_404(User, id=user_id)
        if _is_mentor(request.user) and not getattr(request.user, 'is_staff', False):
            if student.mentor_id != request.user.id:
                raise PermissionDenied("Vous n'êtes pas le mentor assigné de cet étudiant.")
        thread, _ = MentoringThread.objects.get_or_create(
            student=student,
            document_type=document_type,
            defaults={'mentor': request.user, 'status': 'in_progress'},
        )
        if not thread.mentor_id:
            thread.mentor = request.user
            thread.save(update_fields=['mentor'])
        serializer = MentoringThreadSerializer(thread)
        return Response(serializer.data)


# --- Discussion Admin–Mentor ---
def _can_access_admin_mentor_thread(request, thread):
    """True si request.user est l'admin ou le mentor du thread."""
    return thread.admin_user_id == request.user.id or thread.mentor_id == request.user.id


class AdminMentorThreadListView(APIView):
    """GET : liste des fils admin–mentor (admin voit les siens, mentor voit les siens)."""
    permission_classes = [IsAdminOrMentor]

    def get(self, request):
        if getattr(request.user, 'is_staff', False):
            qs = AdminMentorThread.objects.filter(admin_user=request.user).select_related('mentor')
        else:
            qs = AdminMentorThread.objects.filter(mentor=request.user).select_related('admin_user')
        serializer = AdminMentorThreadListSerializer(qs.order_by('-updated_at'), many=True)
        return Response(serializer.data)


class AdminMentorThreadGetOrCreateView(APIView):
    """POST : (admin seulement) get or create un fil avec un mentor. Body: mentor_id."""
    permission_classes = [IsAdminOrMentor]

    def post(self, request):
        if not getattr(request.user, 'is_staff', False):
            raise PermissionDenied("Seul l'admin peut initier une discussion avec un mentor.")
        mentor_id = request.data.get("mentor_id")
        if not mentor_id:
            return Response({"error": "mentor_id requis."}, status=status.HTTP_400_BAD_REQUEST)
        mentor = get_object_or_404(User, id=mentor_id, role=User.Role.MENTOR)
        thread, _ = AdminMentorThread.objects.get_or_create(
            admin_user=request.user,
            mentor=mentor,
            defaults={},
        )
        serializer = AdminMentorThreadSerializer(thread)
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class AdminMentorThreadDetailView(APIView):
    """GET : détail du fil + messages. POST : envoyer un message (content)."""
    permission_classes = [IsAdminOrMentor]

    def _get_thread(self, request, thread_id):
        thread = get_object_or_404(AdminMentorThread, id=thread_id)
        if not _can_access_admin_mentor_thread(request, thread):
            raise PermissionDenied("Vous n'avez pas accès à cette discussion.")
        return thread

    def get(self, request, thread_id):
        thread = self._get_thread(request, thread_id)
        serializer = AdminMentorThreadSerializer(thread)
        return Response(serializer.data)

    def post(self, request, thread_id):
        """Envoyer un message (admin ou mentor)."""
        thread = self._get_thread(request, thread_id)
        content = (request.data.get("content") or "").strip()
        if not content:
            return Response({"error": "Le message ne peut pas être vide."}, status=status.HTTP_400_BAD_REQUEST)
        msg = AdminMentorMessage.objects.create(
            thread=thread,
            sender=request.user,
            content=content,
        )
        thread.save(update_fields=['updated_at'])
        return Response(AdminMentorMessageSerializer(msg).data, status=status.HTTP_201_CREATED)
