from rest_framework import status
from rest_framework.exceptions import ValidationError

from api.models import EsExamRequirement, EsStudent, EsStudentGroup
from api.translation import __
from api.utils import get_exception_detail, log_critical_error
from api.validator import BaseValidator
from api.views.admin.base import AdminApiBase


class ExamRequirementUpdateStudentRules(AdminApiBase):
    list_default_order_column = "id"
    
    def validate_request(self, request):
        rules = {
            "id": "nullable|array|exists:api.EsExamRequirement,id",
            "filter": "nullable",
            "page": "nullable",
            "per_page": "nullable",
            "sort_by": "nullable",
            "order_by": "nullable",
        }
        attribute = {}

        validator = BaseValidator(request.data, rules, attribute)
        error = validator.validate()
        if error:
            raise ValidationError(error)

    def custom_listing_filter(self, request, model):
        filters = request.data.get("filter")
        if filters:
            for key, val in filters.items():
                if val == "" or val is None:
                    continue
                match key:
                    case "code" | "name":
                        filter_kwargs = {f"{key}__icontains": val}
                        model = model.filter(**filter_kwargs)
                    case "student_group_id" | "need_extra_provision":
                        if key == "student_group_id":
                            if isinstance(val, (list, tuple)):
                                model = model.filter(student_group_links__student_group_id__in=val).distinct()
                            else:
                                model = model.filter(student_group_links__student_group_id=val).distinct()
                        elif isinstance(val, (list, tuple)):
                            filter_kwargs = {f"{key}__in": val}
                            model = model.filter(**filter_kwargs)
                        else:
                            filter_kwargs = {key: val}
                            model = model.filter(**filter_kwargs)
                    case "is_scheduled":
                        if isinstance(val, str):
                            is_sch = val.lower() in ("true", "1", "yes", "y")
                        else:
                            is_sch = bool(val)
                        model = model.filter(is_scheduled=is_sch)
        return model

    def post(self, request):
        try:
            self.api_log_skip_outgoing_data = True
            self.validate_request(request)

            ids = request.data.get("id")
            if not ids:
                ids = []

            sort_by = request.data.get("sort_by") or "id"
            order_by = request.data.get("order_by") or "desc"
            
            prefetch_sort_by = "id" if sort_by == "is_scheduled" else sort_by
            
            if str(order_by).lower() == "desc":
                order_str = f"-student__{prefetch_sort_by}"
            else:
                order_str = f"student__{prefetch_sort_by}"

            obj = None
            if isinstance(ids, (list, tuple)) and len(ids) == 1:
                from django.db.models import Prefetch
                from api.models import EsExamRequirementStudent
                
                prefetch_qs = EsExamRequirementStudent.objects.select_related("student").order_by(order_str)

                obj = (
                    EsExamRequirement.objects
                    .prefetch_related(Prefetch("esexamrequirementstudent_set", queryset=prefetch_qs))
                    .filter(id__in=ids)
                    .first()
                )

            info = None
            if obj:
                student_ids = [
                    relation.student_id
                    for relation in obj.esexamrequirementstudent_set.all()
                    if relation.student_id is not None
                ]
                info = {
                    "code": obj.code,
                    "name": obj.name,
                    "student": student_ids,
                }

            students_query = (
                EsStudent.objects
                .select_related("student_group")
                .prefetch_related("student_group_links__student_group")
                .filter(status=EsStudent.STATUS_TO_CODE["active"])
            )
            
            from django.db.models import Exists, OuterRef, Value, BooleanField
            from api.models import EsExamRequirementStudent
            if ids:
                students_query = students_query.annotate(
                    is_scheduled=Exists(
                        EsExamRequirementStudent.objects.filter(
                            exam_requirement_id__in=ids,
                            student_id=OuterRef('pk')
                        )
                    )
                )
            else:
                students_query = students_query.annotate(
                    is_scheduled=Value(False, output_field=BooleanField())
                )
            
            students_query = self.custom_listing_filter(request, students_query)
            paginated_details = self.listing_pagination(request, students_query)
            
            student_data = []
            for val in paginated_details["paginated_data"]:
                student_data.append({
                    "id": val.id,
                    "code": val.code,
                    "name": val.name,
                    "student_group_id": val.student_group_id,
                    "student_group_name": val.student_group.name if val.student_group else None,
                    "student_group_ids": [
                        link.student_group_id for link in val.student_group_links.all()
                    ],
                    "is_scheduled": getattr(val, "is_scheduled", False),
                    "need_extra_provision": val.need_extra_provision,
                })

            sg_order_by = "-id" if str(request.data.get("order_by") or "desc").lower() == "desc" else "id"

            data = {
                "delete_confirmation_api": False,
                "allow_remove": [
                    "student_id",
                    "student_group_id",
                    "student_group_ids",
                ],
                "student": student_data,
                "student_group": list(
                    EsStudentGroup.objects
                    .order_by(sg_order_by)
                    .values("id", "code", "name")
                ),
                "page": paginated_details["page"],
                "per_page": request.data.get("per_page") or self.default_per_page,
                "total": paginated_details["total"],
            }

            response = {
                "info": info,
                "rules": data,
            }

            return self.api_response(data=response)
        except ValidationError as e:
            first_message = e.detail["error"]
            errors = e.detail["errors"]
            return self.api_response(error=first_message, errors=errors, code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            e_details = get_exception_detail(e)
            log_critical_error(user_id=None, descr=e_details["descr"], url=e_details["url"], trace=e_details["trace"])
            return self.api_response(error=__("message.internal_server_error"), code=status.HTTP_500_INTERNAL_SERVER_ERROR)