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 _


# 导入必要的模块：
# - admin: Django 管理后台核心模块
# - DELETION: 表示删除操作的常量
# - ContentType: 用于处理模型的通用外键关系
# - reverse, NoReverseMatch: URL 反向解析相关工具
# - escape: HTML 转义函数，防止 XSS
# - mark_safe: 标记字符串为安全 HTML（不转义）
# - gettext_lazy: 国际化文本标记

#wwc
class LogEntryAdmin(admin.ModelAdmin):
    """
    自定义 Django 管理后台中日志条目（LogEntry）的管理界面。
    用于展示用户在后台执行的操作记录（如添加、修改、删除）。
    此类增强了默认的 LogEntry 显示功能，支持链接跳转、权限控制等。
    """

    # 在列表页右侧显示按内容类型（即模型）过滤的侧边栏
    list_filter = [
        'content_type'
    ]

    # 支持通过对象表示名（object_repr）和变更消息（change_message）进行搜索
    search_fields = [
        'object_repr',
        'change_message'
    ]

    # 设置列表页中可点击进入编辑的字段链接
    list_display_links = [
        'action_time',  # 操作时间
        'get_change_message',  # 变更消息
    ]

    # 定义列表页显示的字段列
    list_display = [
        'action_time',  # 操作发生的时间
        'user_link',  # 执行操作的用户（带链接）
        'content_type',  # 操作的对象类型（如 blog.Article）
        'object_link',  # 被操作的对象实例（带链接）
        'get_change_message',  # 操作详情消息
    ]
#wwc
    def has_add_permission(self, request):
        """
        控制是否允许添加新的日志条目。

        日志由系统自动生成，不允许手动添加。

        参数:
            request: 当前 HTTP 请求对象

        返回:
            bool: 始终返回 False，禁止添加权限
        """
        return False
#wwc
    def has_change_permission(self, request, obj=None):
        """
        控制是否允许修改日志条目。

        仅超级用户或拥有 'admin.change_logentry' 权限的用户可以查看（GET 请求），
        但不允许通过 POST 请求修改（即不可编辑保存）。

        参数:
            request: 当前 HTTP 请求对象
            obj: 当前操作的日志对象（可选）

        返回:
            bool: 是否具有更改权限
        """
        return (
                request.user.is_superuser or
                request.user.has_perm('admin.change_logentry')
        ) and request.method != 'POST'
#wwc
    def has_delete_permission(self, request, obj=None):
        """
        控制是否允许删除日志条目。

        出于审计和安全考虑，禁止删除任何日志记录。

        参数:
            request: 当前 HTTP 请求对象
            obj: 当前操作的日志对象（可选）

        返回:
            bool: 始终返回 False，禁止删除权限
        """
        return False
#wwc
    def object_link(self, obj):
        """
        将被操作对象的名称转换为可点击的超链接（如果可能）。

        如果操作不是删除（DELETION），且 content_type 存在，则尝试生成指向该对象
        在管理后台编辑页面的链接。否则仅显示原始文本。

        参数:
            obj (LogEntry): 日志条目实例

        返回:
            str: HTML 安全的链接或纯文本
        """
        object_link = escape(obj.object_repr)  # 转义原始对象表示，防止 XSS
        content_type = obj.content_type

        if obj.action_flag != DELETION and content_type is not None:
            # 尝试生成链接
            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:
                # 如果 URL 反向解析失败（如模型未注册到 admin），则使用原始文本
                pass
        return mark_safe(object_link)  # 标记为安全 HTML 输出

    # 设置此字段在列表页可排序，排序依据为数据库字段 'object_repr'
    object_link.admin_order_field = 'object_repr'
    # 设置此字段在列表页显示的列标题（支持国际化）
    object_link.short_description = _('object')
#wwc
    def user_link(self, obj):
        """
        将操作用户的名称转换为可点击的超链接，指向该用户在管理后台的编辑页面。

        参数:
            obj (LogEntry): 日志条目实例

        返回:
            str: HTML 安全的用户链接或纯文本
        """
        content_type = ContentType.objects.get_for_model(type(obj.user))  # 获取用户模型的 ContentType
        user_link = escape(force_str(obj.user))  # 转义用户名
        try:
            # 生成用户管理页面的 URL
            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:
            # 如果无法生成链接（如 auth.User 未正确注册），则使用原始文本
            pass
        return mark_safe(user_link)  # 标记为安全 HTML 输出

    # 设置此字段在列表页可排序，排序依据为数据库字段 'user'
    user_link.admin_order_field = 'user'
    # 设置此字段在列表页显示的列标题（支持国际化）
    user_link.short_description = _('user')
#wwc
    def get_queryset(self, request):
        """
        自定义查询集，优化数据库查询性能。

        使用 prefetch_related 提前加载 content_type 外键关联数据，
        避免在列表渲染时产生 N+1 查询问题。

        参数:
            request: 当前 HTTP 请求对象

        返回:
            QuerySet: 优化后的 LogEntry 查询集
        """
        queryset = super(LogEntryAdmin, self).get_queryset(request)
        return queryset.prefetch_related('content_type')
#wwc
    def get_actions(self, request):
        """
        自定义可用的操作列表（如批量删除）。

        移除默认的 "删除选中项" 操作，因为已通过 has_delete_permission 禁止删除，
        此处再次确保该操作不会出现在操作下拉菜单中。

        参数:
            request: 当前 HTTP 请求对象

        返回:
            dict: 过滤后的可用操作字典
        """
        actions = super(LogEntryAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions