from django.utils import timezone
from rest_framework import status
from rest_framework.exceptions import ValidationError

from api.models import AuditTrail, AuditTrailDetails
from api.models.es_session import EsSession
from api.translation import __
from api.utils import get_exception_detail, get_ip, log_critical_error
from api.validator import BaseValidator
from api.views.admin.base import AdminApiBase


class SessionUpdate(AdminApiBase):
    def validate_request(self, request):
        rules = {
            "id": "required|array|exists:api.EsSession,id",
        }

        attribute = {}

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

        rules = {
            "name": "nullable",
            # "location_id": "nullable|exists:api.EsLocation,id",
            "description": "nullable",
            # "start_time": "nullable|datetime",
            # "duration": "nullable|time",
            # "students_enrolled": "nullable|integer|gte:0",
            "invigilators_required": "nullable|integer|gte:0",
        }

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

        return EsSession.objects.filter(id__in=request.data.get("id"))

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

            action = "session_update"
            old_new_data = {
                "new_data": {},
                "old_data": {},
            }
            updated = False
            update_fields = {}

            ignore_fields = ["id", "timestamp", "signature", "location_id", "start_time", "duration", "students_enrolled"]
            valid_fields = {f.column for f in EsSession._meta.fields}
            for key, val in request.data.items():
                if key not in ignore_fields and key in valid_fields:
                    updated = True
                    update_fields[key] = val

            if updated and update_fields:
                for obj in edit_obj:
                    for key, val in update_fields.items():
                        old_val = getattr(obj, key)
                        if str(old_val) != str(val):
                            old_new_data.setdefault("old_data", {}).setdefault(obj.id, {})[key] = old_val
                            old_new_data.setdefault("new_data", {}).setdefault(obj.id, {})[key] = val

                update_fields["updated_by"] = request.user.id
                update_fields["updated_at"] = timezone.now()
                edit_obj.update(**update_fields)

            if old_new_data["old_data"] or old_new_data["new_data"]:
                audit_trail = AuditTrail.objects.create(
                    user_id=request.user.id,
                    type=self.audit_type,
                    ip_address=get_ip(request),
                )

                remark_param = {
                    "name": ",".join(edit_obj.values_list("name", flat=True)),
                }

                AuditTrailDetails.custom_insert(
                    audit_trail=audit_trail,
                    action=action,
                    remark_param=remark_param,
                    new_data=old_new_data["new_data"],
                    old_data=old_new_data["old_data"],
                )

            response = {}

            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)