from datetime import date

from django.db.models import Avg, Count, Max, Q
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from accounts.permissions import IsAdminOrInstructor
from operations.models import Class
from learning.models import Attempt, LearningProfile, Question, Recommendation, TopicMastery
from learning.serializers import (
    AttemptSerializer,
    LearningProfileSerializer,
    QuestionSerializer,
    RecommendationSerializer,
    TopicMasterySerializer,
)
from learning import services


class QuestionViewSet(viewsets.ModelViewSet):
    serializer_class = QuestionSerializer
    filterset_fields = ["course", "topic", "difficulty", "question_type", "is_published"]
    search_fields = ["statement", "skills"]

    def get_permissions(self):
        if self.request.method in ("GET", "HEAD", "OPTIONS"):
            return [IsAuthenticated()]
        return [IsAdminOrInstructor()]

    def get_queryset(self):
        queryset = Question.objects.select_related("course", "topic")
        if self.request.user.is_admin or self.request.user.is_instructor:
            return queryset
        return queryset.filter(is_published=True)


class AttemptViewSet(viewsets.ModelViewSet):
    serializer_class = AttemptSerializer
    filterset_fields = ["question", "is_correct", "question__topic"]
    search_fields = ["question__statement"]

    def get_queryset(self):
        user = self.request.user
        if user.is_admin:
            return Attempt.objects.select_related("student", "question", "question__topic")
        if user.is_instructor:
            return Attempt.objects.filter(
                question__course__classes__instructor=user
            ).select_related("student", "question", "question__topic")
        return Attempt.objects.filter(student=user).select_related(
            "student", "question", "question__topic"
        )

    def perform_create(self, serializer):
        question = serializer.validated_data["question"]
        answer = serializer.validated_data.get("answer", "")
        time_spent = serializer.validated_data.get("time_spent", 0)
        is_correct = answer.strip().lower() == question.correct_answer.strip().lower()
        services.record_attempt(
            student=self.request.user,
            question=question,
            answer=answer,
            is_correct=is_correct,
            time_spent=time_spent,
        )

    @action(detail=False, methods=["get"])
    def recent_errors(self, request):
        errors = (
            self.get_queryset()
            .filter(is_correct=False)
            .order_by("-created_at")[:20]
        )
        serializer = self.get_serializer(errors, many=True)
        return Response(serializer.data)


class TopicMasteryViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = TopicMasterySerializer
    filterset_fields = ["topic", "topic__course"]

    def get_queryset(self):
        user = self.request.user
        profile = services.get_or_create_profile(user)
        if user.is_admin:
            return TopicMastery.objects.select_related("profile", "topic", "topic__course")
        if user.is_instructor:
            return TopicMastery.objects.filter(
                profile__student__enrollments__klass__instructor=user
            ).select_related("profile", "topic", "topic__course").distinct()
        return TopicMastery.objects.filter(profile=profile).select_related(
            "profile", "topic", "topic__course"
        )


class LearningProfileViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = LearningProfileSerializer

    def get_queryset(self):
        user = self.request.user
        if user.is_admin:
            return LearningProfile.objects.prefetch_related("masteries", "masteries__topic")
        return LearningProfile.objects.filter(student=user).prefetch_related(
            "masteries", "masteries__topic"
        )


class RecommendationViewSet(viewsets.ModelViewSet):
    serializer_class = RecommendationSerializer
    filterset_fields = ["topic", "question", "status"]

    def get_queryset(self):
        user = self.request.user
        if user.is_admin:
            return Recommendation.objects.select_related("topic", "question")
        return Recommendation.objects.filter(student=user).select_related("topic", "question")

    def perform_create(self, serializer):
        serializer.save(student=self.request.user)

    @action(detail=False, methods=["post"])
    def generate(self, request):
        topic_id = request.data.get("topic")
        topic = None
        if topic_id:
            from operations.models import Topic

            topic = get_object_or_404(Topic, pk=topic_id)
        recommendation = services.recommend_and_store(request.user, topic=topic)
        if recommendation is None:
            return Response({"detail": "Não há questões disponíveis."}, status=404)
        return Response(self.get_serializer(recommendation).data)


class StudentDashboardView(viewsets.ViewSet):
    """Dashboard do estudante — 'O que devo fazer agora?' (CONTEXT.md, secção 9)."""

    permission_classes = [IsAuthenticated]

    def list(self, request):
        user = request.user
        profile = services.get_or_create_profile(user)

        classes = user.enrollments.filter(status="active").select_related(
            "klass", "klass__course", "klass__instructor"
        )
        from operations.models import Event

        events = Event.objects.filter(status="active", date__gte=date.today())

        masteries = list(
            profile.masteries.select_related("topic", "topic__course").order_by("mastery")
        )
        difficult_topics = [m for m in masteries if m.mastery < services.THRESHOLD_REINFORCE][:3]

        recent_errors = list(
            user.attempts.filter(is_correct=False)
            .select_related("question", "question__topic")
            .order_by("-created_at")[:5]
        )

        next_step = services.next_step_summary(user)

        total_mastery = (
            sum(m.mastery for m in masteries) / len(masteries) if masteries else None
        )

        data = {
            "classes": [
                {
                    "id": e.klass.id,
                    "name": e.klass.name,
                    "course": e.klass.course.name,
                    "instructor": e.klass.instructor.get_full_name(),
                    "schedule": e.klass.schedule,
                }
                for e in classes
            ],
            "upcoming_events": [
                {
                    "id": ev.id,
                    "title": ev.title,
                    "date": ev.date,
                    "time": ev.time,
                }
                for ev in events[:5]
            ],
            "progress": {
                "overall": round(total_mastery, 4) if total_mastery is not None else None,
                "topics_tracked": len(masteries),
            },
            "needs_attention": [
                {
                    "topic": m.topic.name,
                    "course": m.topic.course.name,
                    "mastery": round(m.mastery, 4),
                }
                for m in difficult_topics
            ],
            "recent_errors": [
                {
                    "question": a.question.id,
                    "statement": a.question.statement,
                    "topic": a.question.topic.name if a.question.topic else None,
                    "created_at": a.created_at,
                }
                for a in recent_errors
            ],
            "next_step": next_step,
        }
        return Response(data)


class InstructorDashboardView(viewsets.ViewSet):
    """
    Dashboard do formador — estado da turma, quem precisa de atenção e o que fazer
    (CONTEXT.md, secção 24).
    """

    permission_classes = [IsAuthenticated]

    def retrieve(self, request, pk=None):
        klass = get_object_or_404(Class, pk=pk)
        if not (request.user.is_admin or request.user == klass.instructor):
            return Response({"detail": "Sem permissão."}, status=403)

        students = klass.enrollments.filter(status="active").values_list(
            "student", flat=True
        )
        masteries = (
            TopicMastery.objects.filter(profile__student__in=students)
            .select_related("topic", "topic__course", "profile__student")
        )
        attempts = Attempt.objects.filter(student__in=students)

        topics = masteries.values("topic__id", "topic__name", "topic__course__name")
        topic_stats = []
        for t in topics:
            rows = masteries.filter(topic_id=t["topic__id"])
            avg = rows.aggregate(avg=Avg("mastery"))["avg"]
            topic_stats.append(
                {
                    "topic": t["topic__name"],
                    "course": t["topic__course__name"],
                    "average_mastery": round(avg, 4) if avg is not None else None,
                }
            )
        topic_stats.sort(key=lambda x: (x["average_mastery"] is None, x["average_mastery"] or 1))

        last_seen = (
            Attempt.objects.filter(student__in=students)
            .values("student")
            .annotate(last=Max("created_at"))
        )
        last_map = {r["student"]: r["last"] for r in last_seen}
        students_needing_attention = []
        for m in masteries.filter(mastery__lt=services.THRESHOLD_REINFORCE).select_related(
            "profile__student"
        ):
            students_needing_attention.append(
                {
                    "student_id": m.profile.student.id,
                    "student": m.profile.student.get_full_name(),
                    "topic": m.topic.name,
                    "mastery": round(m.mastery, 4),
                }
            )
        attention_by_student = {}
        for item in students_needing_attention:
            sid = item["student_id"]
            attention_by_student.setdefault(sid, {"student": item["student"], "low_mastery_topics": []})
            attention_by_student[sid]["low_mastery_topics"].append(item["topic"])

        return Response(
            {
                "class": {
                    "id": klass.id,
                    "name": klass.name,
                    "course": klass.course.name,
                },
                "overview": {
                    "active_students": len(students),
                    "total_attempts": attempts.count(),
                    "topics_tracked": topic_stats,
                    "problematic_topics": topic_stats[:3],
                },
                "students_needing_attention": [
                    {
                        "student": v["student"],
                        "low_mastery_topics": v["low_mastery_topics"],
                        "last_activity": last_map.get(k),
                    }
                    for k, v in attention_by_student.items()
                ],
                "suggestions": [
                    {
                        "topic": t["topic"],
                        "action": "Realizar sessão de reforço neste tópico.",
                    }
                    for t in topic_stats[:3]
                ],
            }
        )
