from django.contrib import admin
from django.contrib.admin.models import DELETION
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse, NoReverseMatch
from django.utils.encoding import force_str
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

class LogEntryAdmin(admin.ModelAdmin):
    """
    sh:
    自定义Admin操作日志管理类，继承自ModelAdmin
    用于在Django Admin后台展示和管理系统操作日志（LogEntry模型）
    优化日志展示格式，提供关联对象/用户的快速链接，限制操作权限
    """
    list_filter = [
        'content_type'
    ]

    search_fields = [
        'object_repr',
        'change_message'
    ]

    list_display_links = [
        'action_time',
        'get_change_message',
    ]
    list_display = [
        'action_time',
        'user_link',
        'content_type',
        'object_link',
        'get_change_message',
    ]

    def has_add_permission(self, request):
        """禁用添加操作：操作日志为系统自动生成，不允许手动添加"""
        return False

    def has_change_permission(self, request, obj=None):
        """
        限制修改权限：仅超级用户或拥有change_logentry权限的用户可查看
        且禁止POST请求（防止通过表单提交修改）
        """
        return (
                request.user.is_superuser or
                request.user.has_perm('admin.change_logentry')
        ) and request.method != 'POST'

    def has_delete_permission(self, request, obj=None):
        """禁用删除操作：操作日志需保留，不允许手动删除"""
        return False

    def object_link(self, obj):
        """
        自定义列表字段：操作对象的名称（带跳转链接）
        非删除操作时，生成对象的Admin编辑页链接；删除操作仅显示对象名称
        """
        object_link = escape(obj.object_repr)
        content_type = obj.content_type

        if obj.action_flag != DELETION and content_type is not None:
            # try returning an actual link instead of object repr string
            try:
                url = reverse(
                    'admin:{}_{}_change'.format(content_type.app_label,
                                                content_type.model),
                    args=[obj.object_id]
                )
                object_link = '<a href="{}">{}</a>'.format(url, object_link)
            except NoReverseMatch:
                pass
        return mark_safe(object_link)

    object_link.admin_order_field = 'object_repr'
    object_link.short_description = _('object')

    def user_link(self, obj):
        """
        自定义列表字段：操作用户的名称（带跳转链接）
        生成用户的Admin编辑页链接，方便快速查看用户信息
        """
        content_type = ContentType.objects.get_for_model(type(obj.user))
        user_link = escape(force_str(obj.user))
        try:
            # try returning an actual link instead of object repr string
            url = reverse(
                'admin:{}_{}_change'.format(content_type.app_label,
                                            content_type.model),
                args=[obj.user.pk]
            )
            user_link = '<a href="{}">{}</a>'.format(url, user_link)
        except NoReverseMatch:
            pass
        return mark_safe(user_link)

    user_link.admin_order_field = 'user'
    user_link.short_description = _('user')

    def get_queryset(self, request):
        """优化查询性能：预加载content_type关联数据，减少数据库查询次数"""
        queryset = super(LogEntryAdmin, self).get_queryset(request)
        return queryset.prefetch_related('content_type')

    def get_actions(self, request):
        """移除批量删除操作：操作日志不允许批量删除"""
        actions = super(LogEntryAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions
