<?php

declare(strict_types=1);

namespace Kylin\AuditLog\Traits;

use Kylin\AuditLog\Models\AuditLog;

/**
 * 审计日志记录 Trait
 *
 * 为 Eloquent 模型自动记录 create/update/delete 操作的审计日志。
 * 记录变更前后的值、操作用户、IP 地址等信息。
 *
 * 合规要求：
 *  - 依据《网络安全法》第二十一条，日志保留 >= 180 天
 *  - 依据《个人信息保护法》第二十八条，写入前自动脱敏敏感字段
 *  - 依据等保 2.0 (GB/T 22239)，审计记录不可篡改
 */
trait Auditable
{
    public static function bootAuditable(): void
    {
        static::created(function ($model) {
            static::logAudit($model, 'created', null, $model->getAttributes());
        });

        static::updated(function ($model) {
            static::logAudit($model, 'updated', $model->getOriginal(), $model->getChanges());
        });

        static::deleted(function ($model) {
            static::logAudit($model, 'deleted', $model->getAttributes(), null);
        });
    }

    private static function logAudit($model, string $event, ?array $old, ?array $new): void
    {
        if (! config('kylin-audit-log.enabled', true)) {
            return;
        }

        // 检查排除的事件类型
        $excludeEvents = config('kylin-audit-log.exclude_events', []);
        if (in_array($event, $excludeEvents, true)) {
            return;
        }

        // 检查排除的模型类
        $excludeModels = config('kylin-audit-log.exclude_models', []);
        $modelClass = get_class($model);
        foreach ($excludeModels as $excludeModel) {
            if ($model instanceof $excludeModel) {
                return;
            }
        }

        // 依据《个人信息保护法》第二十八条，写入前对敏感字段脱敏
        $old = AuditLog::redactSensitiveFields($old ?? []);
        $new = AuditLog::redactSensitiveFields($new ?? []);

        // 获取租户 ID（多租户场景）
        $tenantId = null;
        $multiTenant = config('kylin-audit-log.multi_tenant', []);
        if (! empty($multiTenant['enabled'])) {
            $tenantId = method_exists($model, 'getTenantId')
                ? $model->getTenantId()
                : (auth()->user()?->tenant_id ?? null);
        }

        AuditLog::create([
            'event'      => $event,
            'model_type' => $modelClass,
            'model_id'   => $model->getKey(),
            'old_values' => $old,
            'new_values' => $new,
            'user_id'    => auth()->id(),
            'ip'         => request()->ip(),
            'user_agent' => request()->userAgent(),
            'url'        => request()->fullUrl(),
            'tenant_id'  => $tenantId,
        ]);
    }
}
