package com.agent.management.service;

import com.agent.management.engine.ExecutionLog;
import com.agent.management.model.entity.ChatMessageLog;
import com.agent.management.repository.ChatMessageLogRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * Agent 对话消息日志 Service。
 *
 * <p>对应设计文档 {@code docs/design/agent-chat-page-design.md} §4.3.3。
 * 承载 {@link ChatMessageLog} 子表的批量写入与按 seq 回放查询。</p>
 *
 * <p>批量写入策略：调用方累积 {@link ExecutionLog} 到缓冲区，缓冲到一定量后一次性 flush。
 * 避免每条日志一次 INSERT 的开销。</p>
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChatMessageLogService {

    /** 缓冲区满阈值：达到此条数立即 flush */
    public static final int FLUSH_THRESHOLD = 50;

    private final ChatMessageLogRepository repo;

    /**
     * 批量写入日志行。
     *
     * @param messageId 关联的 assistant 消息 id
     * @param logs      待写入的日志（本方法不修改入参；调用方根据返回值决定是否清空缓冲区）
     * @param startSeq  起始 seq（首次为 0，后续为已写入条数）
     * @return 实际写入的行数；失败时为 0
     */
    @Transactional
    public int appendBatch(Long messageId, List<ExecutionLog> logs, int startSeq) {
        if (logs == null || logs.isEmpty()) {
            return 0;
        }
        List<ChatMessageLog> rows = new ArrayList<>(logs.size());
        int seq = startSeq;
        for (ExecutionLog log : logs) {
            rows.add(toRow(messageId, seq++, log));
        }
        repo.saveAll(rows);
        return rows.size();
    }

    /**
     * 按 seq 排序返回所有日志行，可直接映射为 ExecutionLog[] 给前端回放。
     */
    public List<ChatMessageLog> findByMessage(Long messageId) {
        return repo.findByMessageIdOrderBySeqAsc(messageId);
    }

    /**
     * 按 kind 筛选（如仅取 tool_call）。
     */
    public List<ChatMessageLog> findByMessageAndKind(Long messageId, String kind) {
        return repo.findByMessageIdAndKindOrderBySeqAsc(messageId, kind);
    }

    /**
     * 当前消息已写入日志行数（用于追加新 batch 时计算 startSeq）。
     */
    public long countByMessage(Long messageId) {
        return repo.countByMessageId(messageId);
    }

    /**
     * 把 {@link ExecutionLog} 的字段拆解到 {@link ChatMessageLog} 的 content/toolName/metaJson 三列。
     *
     * <p>字段语义对照（与 {@code ExecutionLog} 工厂方法定义一致）：</p>
     * <ul>
     *   <li>INFO/THINKING/STATUS/ERROR：message=正文，detail=null → content=message</li>
     *   <li>TOOL_CALL/TOOL_RESULT：message=工具名，detail=参数或结果 → toolName=message, content=detail</li>
     *   <li>STEP/TOOL_PROGRESS/TODO_UPDATE/CLARIFY_REQUEST：message=事件类型/问句，detail=JSON → content=message, metaJson=detail</li>
     * </ul>
     */
    private String toKind(ExecutionLog log) {
        if (log == null || log.getType() == null) {
            return "info";
        }
        return log.getType().name().toLowerCase();
    }

    /** 拆解单条 log 为存储行（与 toKind 配套使用） */
    private ChatMessageLog toRow(Long messageId, int seq, ExecutionLog log) {
        ChatMessageLog row = new ChatMessageLog();
        row.setMessageId(messageId);
        row.setSeq(seq);
        row.setKind(toKind(log));
        ExecutionLog.Type type = log.getType();
        if (type == ExecutionLog.Type.TOOL_CALL || type == ExecutionLog.Type.TOOL_RESULT) {
            row.setToolName(log.getMessage());
            row.setContent(log.getDetail());
        } else if (type == ExecutionLog.Type.STEP
                || type == ExecutionLog.Type.TOOL_PROGRESS
                || type == ExecutionLog.Type.TODO_UPDATE
                || type == ExecutionLog.Type.CLARIFY_REQUEST) {
            row.setContent(log.getMessage());
            row.setMetaJson(log.getDetail());
        } else {
            row.setContent(log.getMessage());
        }
        return row;
    }
}
