from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db import transaction
from django.db.models import Q
from django.utils import timezone

from people.models import Teacher
from academics.models import AcademicClass, SubjectTeacher
from announcements.models import StudentAnnouncement, AnnouncementType

import logging
logger = logging.getLogger(__name__)


def _get_teacher(request):
    return Teacher.objects.get(external_user_id=request.user.id)


def _teacher_class_ids(teacher):
    """Return IDs of all classes this teacher teaches (subject teacher + class teacher)."""
    subject_class_ids = SubjectTeacher.objects.filter(
        teacher=teacher
    ).values_list("academic_class_id", flat=True)

    class_teacher_ids = AcademicClass.objects.filter(
        class_teacher=teacher
    ).values_list("id", flat=True)

    return set(subject_class_ids) | set(class_teacher_ids)


class TeacherAnnouncementTypesView(APIView):
    """
    GET /teacher/announcements/types/
    Returns active announcement types for the dropdown.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        types = AnnouncementType.objects.filter(is_active=True).values(
            "id", "name", "code"
        )
        return Response({"success": True, "results": list(types)})


class TeacherStudentAnnouncementListCreateView(APIView):
    """
    GET  /teacher/announcements/student/   — list this teacher's announcements
    POST /teacher/announcements/student/   — create a new announcement
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = _get_teacher(request)
        except Teacher.DoesNotExist:
            return Response({"success": False, "message": "Teacher profile not found."},
                            status=status.HTTP_404_NOT_FOUND)

        qs = StudentAnnouncement.objects.filter(
            created_by_external_user_id=request.user.id
        ).select_related("announcement_type", "academic_class")

        # Filters
        class_id = request.query_params.get("academic_class")
        if class_id:
            qs = qs.filter(academic_class_id=class_id)

        priority = request.query_params.get("priority")
        if priority:
            qs = qs.filter(priority=priority)

        is_active = request.query_params.get("is_active")
        if is_active is not None:
            qs = qs.filter(is_active=is_active.lower() == "true")

        search = request.query_params.get("search", "").strip()
        if search:
            qs = qs.filter(Q(title__icontains=search) | Q(message__icontains=search))

        results = [
            {
                "id": a.id,
                "title": a.title,
                "message": a.message,
                "announcement_type": a.announcement_type_id,
                "announcement_type_name": a.announcement_type.name if a.announcement_type else None,
                "academic_class": a.academic_class_id,
                "class_name": str(a.academic_class) if a.academic_class else None,
                "is_for_all_students": a.is_for_all_students,
                "priority": a.priority,
                "expire_on": a.expire_on,
                "is_active": a.is_active,
                "from_role": a.from_role,
                "created_at": a.created_at,
                "updated_at": a.updated_at,
            }
            for a in qs
        ]
        return Response({"success": True, "results": results})

    @transaction.atomic
    def post(self, request):
        try:
            teacher = _get_teacher(request)
        except Teacher.DoesNotExist:
            return Response({"success": False, "message": "Teacher profile not found."},
                            status=status.HTTP_404_NOT_FOUND)

        data = request.data
        errors = {}

        title = (data.get("title") or "").strip()
        message = (data.get("message") or "").strip()
        announcement_type_id = data.get("announcement_type")
        academic_class_id = data.get("academic_class")
        priority = data.get("priority", "medium")
        expire_on = data.get("expire_on") or None
        is_active = data.get("is_active", True)

        if not title:
            errors["title"] = "Title is required."
        if not message:
            errors["message"] = "Message is required."
        if not announcement_type_id:
            errors["announcement_type"] = "Announcement type is required."
        if not academic_class_id:
            errors["academic_class"] = "Select a class."

        if errors:
            return Response({"success": False, "errors": errors},
                            status=status.HTTP_400_BAD_REQUEST)

        # Validate class belongs to this teacher
        allowed_ids = _teacher_class_ids(teacher)
        if int(academic_class_id) not in allowed_ids:
            return Response(
                {"success": False, "message": "You do not teach this class."},
                status=status.HTTP_403_FORBIDDEN,
            )

        try:
            ann_type = AnnouncementType.objects.get(id=announcement_type_id, is_active=True)
        except AnnouncementType.DoesNotExist:
            return Response({"success": False, "message": "Invalid announcement type."},
                            status=status.HTTP_400_BAD_REQUEST)

        announcement = StudentAnnouncement.objects.create(
            title=title,
            message=message,
            announcement_type=ann_type,
            academic_class_id=academic_class_id,
            is_for_all_students=False,
            priority=priority,
            expire_on=expire_on,
            is_active=is_active,
            from_role="Teacher",
            created_by_external_user_id=request.user.id,
        )

        return Response(
            {
                "success": True,
                "message": "Announcement sent successfully.",
                "data": {
                    "id": announcement.id,
                    "title": announcement.title,
                    "class_name": str(announcement.academic_class),
                    "created_at": announcement.created_at,
                },
            },
            status=status.HTTP_201_CREATED,
        )


class TeacherStudentAnnouncementDetailView(APIView):
    """
    GET    /teacher/announcements/student/<id>/
    PUT    /teacher/announcements/student/<id>/
    PATCH  /teacher/announcements/student/<id>/
    DELETE /teacher/announcements/student/<id>/
    """
    permission_classes = [IsAuthenticated]

    def _get_obj(self, pk, user_id):
        try:
            return StudentAnnouncement.objects.select_related(
                "announcement_type", "academic_class"
            ).get(id=pk, created_by_external_user_id=user_id)
        except StudentAnnouncement.DoesNotExist:
            return None

    def get(self, request, pk):
        obj = self._get_obj(pk, request.user.id)
        if not obj:
            return Response({"success": False, "message": "Announcement not found."},
                            status=status.HTTP_404_NOT_FOUND)
        return Response({
            "success": True,
            "data": {
                "id": obj.id,
                "title": obj.title,
                "message": obj.message,
                "announcement_type": obj.announcement_type_id,
                "announcement_type_name": obj.announcement_type.name if obj.announcement_type else None,
                "academic_class": obj.academic_class_id,
                "class_name": str(obj.academic_class) if obj.academic_class else None,
                "priority": obj.priority,
                "expire_on": obj.expire_on,
                "is_active": obj.is_active,
                "from_role": obj.from_role,
                "created_at": obj.created_at,
                "updated_at": obj.updated_at,
            },
        })

    @transaction.atomic
    def put(self, request, pk):
        obj = self._get_obj(pk, request.user.id)
        if not obj:
            return Response({"success": False, "message": "Announcement not found."},
                            status=status.HTTP_404_NOT_FOUND)

        data = request.data
        errors = {}

        title = (data.get("title") or "").strip()
        message = (data.get("message") or "").strip()
        announcement_type_id = data.get("announcement_type")
        academic_class_id = data.get("academic_class")

        if not title:   errors["title"] = "Title is required."
        if not message: errors["message"] = "Message is required."
        if not announcement_type_id: errors["announcement_type"] = "Required."
        if not academic_class_id:    errors["academic_class"] = "Required."
        if errors:
            return Response({"success": False, "errors": errors},
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            teacher = _get_teacher(request)
        except Teacher.DoesNotExist:
            return Response({"success": False, "message": "Teacher profile not found."},
                            status=status.HTTP_404_NOT_FOUND)

        allowed_ids = _teacher_class_ids(teacher)
        if int(academic_class_id) not in allowed_ids:
            return Response({"success": False, "message": "You do not teach this class."},
                            status=status.HTTP_403_FORBIDDEN)

        obj.title = title
        obj.message = message
        obj.announcement_type_id = announcement_type_id
        obj.academic_class_id = academic_class_id
        obj.priority = data.get("priority", obj.priority)
        obj.expire_on = data.get("expire_on") or None
        obj.is_active = data.get("is_active", obj.is_active)
        obj.save()

        return Response({"success": True, "message": "Announcement updated."})

    def patch(self, request, pk):
        obj = self._get_obj(pk, request.user.id)
        if not obj:
            return Response({"success": False, "message": "Announcement not found."},
                            status=status.HTTP_404_NOT_FOUND)

        if "is_active" in request.data:
            obj.is_active = request.data["is_active"]
            obj.save(update_fields=["is_active"])

        return Response({"success": True, "message": "Updated."})

    def delete(self, request, pk):
        obj = self._get_obj(pk, request.user.id)
        if not obj:
            return Response({"success": False, "message": "Announcement not found."},
                            status=status.HTTP_404_NOT_FOUND)
        obj.delete()
        return Response({"success": True, "message": "Announcement deleted."})
