from django.db.models import Count, 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 IsAdmin, IsAdminOrInstructor, IsAdminOrReadOnly
from operations.models import (
    Class,
    Course,
    Enrollment,
    Event,
    EventEnrollment,
    Material,
    Payment,
    Topic,
)
from operations.serializers import (
    ClassSerializer,
    CourseSerializer,
    EnrollmentSerializer,
    EventEnrollmentSerializer,
    EventSerializer,
    MaterialSerializer,
    PaymentSerializer,
    TopicSerializer,
)


class CourseViewSet(viewsets.ModelViewSet):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    permission_classes = [IsAdminOrReadOnly]
    filterset_fields = ["is_active"]
    search_fields = ["name", "code"]


class TopicViewSet(viewsets.ModelViewSet):
    serializer_class = TopicSerializer
    permission_classes = [IsAdminOrReadOnly]
    filterset_fields = ["course", "parent"]
    search_fields = ["name"]

    def get_queryset(self):
        return Topic.objects.select_related("course").all()


class ClassViewSet(viewsets.ModelViewSet):
    serializer_class = ClassSerializer
    permission_classes = [IsAdminOrReadOnly]
    filterset_fields = ["course", "instructor", "is_active", "mode"]
    search_fields = ["name", "course__name", "instructor__first_name", "instructor__last_name"]

    def get_queryset(self):
        queryset = Class.objects.select_related("course", "instructor")
        user = self.request.user
        if not user.is_authenticated:
            return queryset.none()
        if user.is_admin:
            return queryset
        if user.is_instructor:
            return queryset.filter(instructor=user)
        # Estudantes: turmas em que estão inscritos
        return queryset.filter(enrollments__student=user).distinct()


class EnrollmentViewSet(viewsets.ModelViewSet):
    serializer_class = EnrollmentSerializer
    filterset_fields = ["status", "klass", "student"]

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

    def get_queryset(self):
        user = self.request.user
        if user.is_admin:
            return Enrollment.objects.select_related("student", "klass", "klass__course", "payment")
        if user.is_instructor:
            return Enrollment.objects.filter(klass__instructor=user).select_related(
                "student", "klass", "klass__course", "payment"
            )
        return Enrollment.objects.filter(student=user).select_related(
            "student", "klass", "klass__course", "payment"
        )

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


class EventViewSet(viewsets.ModelViewSet):
    serializer_class = EventSerializer
    filterset_fields = ["status", "mode", "date"]
    search_fields = ["title", "description"]

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

    def get_queryset(self):
        return Event.objects.select_related("instructor").all()


class EventEnrollmentViewSet(viewsets.ModelViewSet):
    serializer_class = EventEnrollmentSerializer
    filterset_fields = ["event", "status"]

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

    def get_queryset(self):
        user = self.request.user
        if user.is_admin:
            return EventEnrollment.objects.select_related("event", "user")
        return EventEnrollment.objects.filter(Q(user=user)).select_related("event", "user")

    def perform_create(self, serializer):
        data = {}
        user = self.request.user
        if user.is_authenticated:
            data["user"] = user
        guest_phone = serializer.validated_data.get("guest_phone", "")
        if not data.get("user") and guest_phone:
            from accounts.models import User

            matched = User.objects.filter(phone=guest_phone).first()
            if matched:
                data["user"] = matched
        serializer.save(**data)


class PaymentViewSet(viewsets.ModelViewSet):
    serializer_class = PaymentSerializer
    filterset_fields = ["status", "method", "enrollment"]

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

    def get_queryset(self):
        user = self.request.user
        if user.is_admin:
            return Payment.objects.select_related("enrollment", "enrollment__student", "enrollment__klass")
        return Payment.objects.filter(enrollment__student=user).select_related(
            "enrollment", "enrollment__student", "enrollment__klass"
        )

    def perform_create(self, serializer):
        serializer.save(confirmed_by=None)


class MaterialViewSet(viewsets.ModelViewSet):
    serializer_class = MaterialSerializer
    filterset_fields = ["course", "topic", "klass", "material_type", "is_public"]
    search_fields = ["title", "description"]

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

    def get_queryset(self):
        user = self.request.user
        queryset = Material.objects.select_related("course", "topic", "klass")
        if user.is_admin:
            return queryset
        # Estudantes/formadores: materiais públicos ou das turmas a que têm acesso
        accessible_classes = (
            Class.objects.filter(Q(enrollments__student=user) | Q(instructor=user))
            if user.is_authenticated
            else Class.objects.none()
        )
        class_ids = list(accessible_classes.values_list("id", flat=True))
        return queryset.filter(Q(is_public=True) | Q(klass_id__in=class_ids)).distinct()
