package com.gzzm.lobster.tool;

import com.gzzm.lobster.audit.AuditLog;
import com.gzzm.lobster.audit.AuditLogDao;
import com.gzzm.lobster.common.IdGenerator;
import com.gzzm.lobster.common.JsonUtil;
import com.gzzm.platform.commons.Tools;
import net.cyan.nest.annotation.Inject;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * ToolAuditLogger —— 工具调用审计 / Tool-call audit logger.
 */
public class ToolAuditLogger {

    @Inject
    private AuditLogDao auditLogDao;

    /** thunwind DAO 跨线程保护 —— 详见 feedback_thunwind_dao_thread_binding */
    private AuditLogDao auditLogDao() {
        try {
            AuditLogDao d = Tools.getBean(AuditLogDao.class);
            if (d != null) return d;
        } catch (Throwable ignore) { /* fallback */ }
        return auditLogDao;
    }

    public void record(ToolContext ctx, String toolName, Map<String, Object> args,
                       String result, int durationMs) {
        try {
            AuditLog log = new AuditLog();
            log.setAuditId(IdGenerator.auditId());
            log.setUserId(ctx.getUserId());
            log.setDeptId(ctx.getDeptId());
            log.setOrgId(ctx.getOrgId());
            log.setThreadId(ctx.getThreadId());
            log.setRunId(ctx.getRunId());
            log.setActionType("tool." + toolName);
            log.setTargetType("tool");
            log.setTargetRef(toolName);
            log.setResult(result);
            Map<String, Object> detail = new LinkedHashMap<>();
            detail.put("args", args);
            detail.put("toolCallId", ctx.getToolCallId());
            String json = JsonUtil.toJson(detail);
            json = truncateUtf8(json, 1800);
            log.setDetailJson(json);
            log.setDurationMs(durationMs);
            log.setCreateTime(new Date());
            auditLogDao().save(log);
        } catch (Throwable t) {
            try { Tools.log("[ToolAuditLogger] failed", t); } catch (Throwable ignore) { /* ignore */ }
        }
    }

    private String truncateUtf8(String value, int maxBytes) {
        if (value == null || maxBytes <= 0) return value;
        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
        if (bytes.length <= maxBytes) return value;
        String suffix = "...";
        int budget = Math.max(0, maxBytes - suffix.getBytes(StandardCharsets.UTF_8).length);
        StringBuilder out = new StringBuilder(Math.min(value.length(), budget));
        int used = 0;
        for (int i = 0; i < value.length();) {
            int cp = value.codePointAt(i);
            String s = new String(Character.toChars(cp));
            int len = s.getBytes(StandardCharsets.UTF_8).length;
            if (used + len > budget) break;
            out.append(s);
            used += len;
            i += Character.charCount(cp);
        }
        return out.append(suffix).toString();
    }
}
