import ast
from unicodedata import name

from rest_framework import status
from rest_framework.exceptions import ValidationError

from api.helper.audit_trail_helper import get_target_model_text
from api.models.audit_trail import AuditTrail
from api.models.audit_trail_details import AuditTrailDetails
from api.models.user import User
from api.translation import __
from api.utils import log_critical_error, get_exception_detail
from api.validator import BaseValidator
from api.views.admin.base import AdminApiBase

class AuditTrailList(AdminApiBase):
    # Override base default "name" sorting because audit_trail has no name field.
    list_default_order_column = "-created_at"

    def validate_request(self, request):
        rules = {
            "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 post(self, request):
        try:
            self.api_log_skip_outgoing_data = True
            self.validate_request(request)
            data = self.get_data(request)
            return self.api_response(data=data)
        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)

    def get_data(self, request):
        details = AuditTrailDetails.objects.select_related("audit_trail")

        filters = request.data.get("filter") or {}
        created_at_from = filters.get("created_at_from")
        created_at_to = filters.get("created_at_to")
        user_name = filters.get("user_name")
        trail_type = filters.get("type")
        trail_id = filters.get("id")
        action = filters.get("action")
        target = filters.get("target")
        audit_trail_type = AuditTrail.TYPE
        audit_trail_type = {value: key for key, value in audit_trail_type.items()}
        
        if created_at_from not in [None, ""]:
            details = details.filter(created_at__gte=created_at_from)

        if created_at_to not in [None, ""]:
            details = details.filter(created_at__lte=created_at_to)

        if user_name not in [None, ""]:
            matching_user_ids = User.objects.filter(
                name__icontains=user_name
            ).values_list("id", flat=True)

            details = details.filter(
                audit_trail__user_id__in=matching_user_ids
            )

        if trail_type not in [None, ""]:
            details = details.filter(audit_trail__type=trail_type)

        if action not in [None, ""]:
            details = details.filter(action=action)

        if target not in [None, ""]:
            details = details.filter(remark_param__icontains=str(target).strip())

        if trail_id not in [None, ""]:
            details = details.filter(id=trail_id)

        paginated_details = self.listing_pagination(request, details)
        total = paginated_details["total"]
        paginated_data = paginated_details["paginated_data"]
        page = paginated_details["page"]

        user_ids = {detail.audit_trail.user_id for detail in paginated_data if detail.audit_trail.user_id}
        user_name_map = {}
        if user_ids:
            user_name_map = dict(User.objects.filter(id__in=user_ids).values_list("id", "name"))

        return_data = []
        for detail in paginated_data:
            trail = detail.audit_trail
            if detail.remark_param:
                if isinstance(detail.remark_param, dict):
                    remark_param = detail.remark_param
                else:
                    try:
                        remark_param = ast.literal_eval(detail.remark_param)
                    except (ValueError, SyntaxError):
                        remark_param = {}
            else:
                remark_param = {}

            if not isinstance(remark_param, dict):
                remark_param = {}

            remark_name = remark_param.get("name")

            if remark_name is None:
                remark_name = remark_param.get("code")

            if remark_name is None:
                remark_name = remark_param.get("ids")

            if isinstance(remark_name, (list, tuple, set)):
                remark_name = ", ".join(map(str, remark_name))
            elif remark_name is None:
                remark_name = ""
            else:
                remark_name = str(remark_name)

            action_text = __(f"audit_trail.action.admin.{detail.action}", **remark_param)

            return_data.append({
                "target": get_target_model_text(detail.action),
                "audit_trail_id": detail.id,
                "user_id": trail.user_id,
                "user_name": user_name_map.get(trail.user_id),
                "type": trail.type,
                "type_text": __(f"audit_trail.type.{audit_trail_type.get(trail.type, '')}"),
                "action": detail.action,
                "action_text": action_text,
                "remark_text": remark_name,
                "remark_param": remark_param,
                "created_at": detail.created_at,
            })

        return {
            "total": total,
            "page": page,
            "data": return_data,
            'rules':{
                "type": [
                    {
                        "id": key,
                        "name": __(f"audit_trail.type.{value}"),
                    }
                    for key, value in audit_trail_type.items()
                ],

                "action": [
                    {
                        "id": key,
                        "name": __(f"audit_trail.action.admin.{key}"),
                    }
                    for key in __("audit_trail.action.admin").keys()
                ],
            }
        }
