package tech.easyflow.agent.runtime.event;

import com.easyagents.agent.runtime.event.AgentRuntimeEvent;
import com.easyagents.agent.runtime.event.AgentRuntimeEventType;
import org.springframework.stereotype.Service;
import tech.easyflow.agent.entity.AgentRunEventRecord;
import tech.easyflow.agent.mapper.AgentRunEventRecordMapper;
import tech.easyflow.core.runtime.ChatRuntimeContext;
import tech.easyflow.core.runtime.ChatRuntimeExtKeys;

import java.math.BigInteger;
import java.time.Instant;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * MySQL Agent 运行事件记录器。
 */
@Service
public class MySqlAgentRunEventRecorder implements AgentRunEventRecorder {

    private final AgentRunEventRecordMapper eventRecordMapper;

    /**
     * 创建记录器。
     *
     * @param eventRecordMapper 事件 Mapper
     */
    public MySqlAgentRunEventRecorder(AgentRunEventRecordMapper eventRecordMapper) {
        this.eventRecordMapper = eventRecordMapper;
    }

    @Override
    public void record(String requestId, ChatRuntimeContext chatContext, AgentRuntimeEvent event) {
        if (event == null || event.getEventType() == null || !shouldPersist(event.getEventType())) {
            return;
        }
        AgentRunEventRecord record = new AgentRunEventRecord();
        record.setTenantId(chatContext == null ? null : chatContext.getTenantId());
        record.setAgentId(resolveAgentId(event, chatContext));
        record.setChatSessionId(chatContext == null ? null : chatContext.getSessionId());
        record.setRoundId(resolveNumber(chatContext, ChatRuntimeExtKeys.CURRENT_ROUND_ID));
        record.setRoundNo(resolveInteger(chatContext, ChatRuntimeExtKeys.CURRENT_ROUND_NO));
        record.setVariantIndex(resolveInteger(chatContext, ChatRuntimeExtKeys.CURRENT_VARIANT_INDEX, 1));
        record.setRequestId(firstText(requestId, stringValue(event.getPayload().get("requestId"))));
        record.setEventId(event.getEventId());
        record.setEventType(event.getEventType().name());
        record.setEventPhase(stringValue(event.getMetadata().get("phase")));
        record.setToolCallId(firstText(event.getToolCallId(), stringValue(event.getPayload().get("toolCallId"))));
        record.setPayloadJson(new LinkedHashMap<>(event.getPayload() == null ? Map.of() : event.getPayload()));
        record.setMetadataJson(new LinkedHashMap<>(event.getMetadata() == null ? Map.of() : event.getMetadata()));
        record.setCreated(toDate(event.getCreatedAt()));
        record.setCreatedBy(chatContext == null ? null : chatContext.getUserId());
        eventRecordMapper.insert(record);
    }

    private boolean shouldPersist(AgentRuntimeEventType type) {
        return type != AgentRuntimeEventType.MESSAGE_DELTA
                && type != AgentRuntimeEventType.REASONING_DELTA
                && type != AgentRuntimeEventType.STARTED
                && type != AgentRuntimeEventType.COMPLETED;
    }

    private BigInteger resolveAgentId(AgentRuntimeEvent event, ChatRuntimeContext chatContext) {
        String agentId = firstText(event.getAgentId(), stringValue(event.getPayload().get("agentId")));
        if (agentId != null && !agentId.isBlank()) {
            try {
                return new BigInteger(agentId);
            } catch (NumberFormatException ignored) {
                return chatContext == null ? null : chatContext.getAssistantId();
            }
        }
        return chatContext == null ? null : chatContext.getAssistantId();
    }

    private BigInteger resolveNumber(ChatRuntimeContext context, String key) {
        Object value = context == null || context.getExt() == null ? null : context.getExt().get(key);
        if (value instanceof BigInteger bigInteger) {
            return bigInteger;
        }
        if (value instanceof Number number) {
            return BigInteger.valueOf(number.longValue());
        }
        String text = stringValue(value);
        if (text == null || text.isBlank()) {
            return null;
        }
        try {
            return new BigInteger(text);
        } catch (NumberFormatException ignored) {
            return null;
        }
    }

    private Integer resolveInteger(ChatRuntimeContext context, String key) {
        return resolveInteger(context, key, null);
    }

    private Integer resolveInteger(ChatRuntimeContext context, String key, Integer defaultValue) {
        Object value = context == null || context.getExt() == null ? null : context.getExt().get(key);
        if (value instanceof Number number) {
            return number.intValue();
        }
        String text = stringValue(value);
        if (text == null || text.isBlank()) {
            return defaultValue;
        }
        try {
            return Integer.parseInt(text);
        } catch (NumberFormatException ignored) {
            return defaultValue;
        }
    }

    private Date toDate(Instant instant) {
        return instant == null ? new Date() : Date.from(instant);
    }

    private String firstText(String left, String right) {
        return left != null && !left.isBlank() ? left : right;
    }

    private String stringValue(Object value) {
        return value == null ? null : String.valueOf(value);
    }
}
