<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Tools\Support;

use App\Models\DberpToolInvocation;
use App\Models\User;
use App\Tools\ToolExecutionContext;
use App\Tools\ToolMetadata;
use App\Tools\ToolResult;
use Illuminate\Support\Facades\Log;
use Throwable;

/**
 * 写入 Tool 调用审计。失败只记日志，不得覆盖原始 ToolResult。
 */
final class ToolInvocationAuditor
{
    /**
     * @param  array<string, mixed>  $input
     */
    public function record(
        string $toolName,
        ToolExecutionContext $context,
        ?ToolMetadata $metadata,
        ToolResult $result,
        int $durationMs,
        array $input = [],
    ): void {
        try {
            $volume = ToolInvocationAuditMetadata::from($input, $result);

            DberpToolInvocation::query()->create([
                'tool_name' => $toolName,
                'tool_version' => $metadata?->version,
                'tool_owner' => $metadata?->owner,
                'actor_user_id' => $this->persistedActorId($context),
                'source' => $context->source->value,
                'client_id' => $this->nullableTrim($context->clientId),
                'session_id' => $this->nullableTrim($context->sessionId),
                'correlation_id' => $context->correlationId,
                'request_id' => $this->nullableTrim($context->requestId),
                'permission_type' => $metadata?->permission->type->value,
                'permission_value' => $metadata?->permission->value,
                'risk' => $metadata?->risk->value,
                'success' => $result->success,
                'error_code' => $result->error?->code->value,
                'duration_ms' => max(0, $durationMs),
                'page' => $volume['page'],
                'per_page' => $volume['per_page'],
                'result_count' => $volume['result_count'],
                'filter_fingerprint' => $volume['filter_fingerprint'],
                'created_at' => now(),
            ]);
        } catch (Throwable $exception) {
            Log::error('dberp.tools.invocation_audit_failed', [
                'tool' => $toolName,
                'correlation_id' => $context->correlationId,
                'detail' => $exception->getMessage(),
            ]);
        }
    }

    private function persistedActorId(ToolExecutionContext $context): ?int
    {
        if (! $context->actor instanceof User) {
            return null;
        }

        $key = $context->actor->getKey();

        if (! is_numeric($key) || (int) $key <= 0) {
            return null;
        }

        $actorId = (int) $key;

        if (! User::query()->whereKey($actorId)->exists()) {
            return null;
        }

        return $actorId;
    }

    private function nullableTrim(?string $value): ?string
    {
        if ($value === null) {
            return null;
        }

        $trimmed = trim($value);

        return $trimmed === '' ? null : $trimmed;
    }
}
