package com.hbasesoft.framework.ai.agent.recorder.model;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.hbasesoft.framework.ai.agent.agent.BaseAgent;

/**
 * 智能体执行记录类，用于跟踪和记录BaseAgent执行过程的详细信息。
 * <p>
 * 数据结构分为三个主要部分：
 * <p>
 * 1. 基本信息 (Basic Info) - id: 记录的唯一标识 - conversationId: 对话唯一标识 - agentName: 智能体名称 - agentDescription: 智能体描述 - startTime:
 * 执行开始时间 - endTime: 执行结束时间
 * <p>
 * 2. 执行过程数据 (Execution Data) - maxSteps: 最大执行步骤数 - currentStep: 当前执行步骤 - status: 执行状态（IDLE, RUNNING, FINISHED） -
 * thinkActSteps: 思考-行动步骤记录列表，每个元素是ThinkActRecord对象 - agentRequest: 输入提示模板
 * <p>
 * 3. 执行结果 (Execution Result) - isCompleted: 是否完成 - isStuck: 是否卡住 - result: 执行结果 - errorMessage: 错误信息（如有）
 *
 * @see BaseAgent
 * @see ThinkActRecord
 */
public class AgentExecutionRecord {

    // Unique identifier of the record
    private Long id;

    // Conversation ID this record belongs to
    private String conversationId;

    // Name of the agent that created this record
    private String agentName;

    // Description information of the agent
    private String agentDescription;

    // Timestamp when execution started
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime startTime;

    // Timestamp when execution ended
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime endTime;

    // Maximum allowed number of steps
    private int maxSteps;

    // Current execution step number
    private int currentStep;

    // Execution status (IDLE, RUNNING, FINISHED)
    private ExecutionStatus status;

    // Record list of think-act steps, existing as sub-steps
    private List<ThinkActRecord> thinkActSteps;

    // Request content for agent execution
    private String agentRequest;

    // Execution result
    private String result;

    // Error message if execution encounters problems
    private String errorMessage;

    // Actual calling model
    private String modelName;

    // Default constructor
    public AgentExecutionRecord() {
        this.thinkActSteps = new ArrayList<>();
        // Ensure ID is generated during initialization
        this.id = generateId();
    }

    // Constructor with parameters
    public AgentExecutionRecord(String conversationId, String agentName, String agentDescription) {
        this.conversationId = conversationId;
        this.agentName = agentName;
        this.agentDescription = agentDescription;
        this.startTime = LocalDateTime.now();
        this.status = ExecutionStatus.IDLE; // Use enum value
        this.currentStep = 0;
        this.thinkActSteps = new ArrayList<>();
        // Ensure ID is generated during initialization
        this.id = generateId();
    }

    /**
     * Add a ThinkActRecord as execution step
     * 
     * @param record ThinkActRecord instance
     */
    public void addThinkActStep(ThinkActRecord record) {
        if (this.thinkActSteps == null) {
            this.thinkActSteps = new ArrayList<>();
        }
        this.thinkActSteps.add(record);
        this.currentStep = this.thinkActSteps.size();
    }

    /**
     * Generate unique ID if not already set
     * 
     * @return Generated or existing ID
     */
    private Long generateId() {
        if (this.id == null) {
            // Use combination of timestamp and random number to generate ID
            long timestamp = System.currentTimeMillis();
            int random = (int) (Math.random() * 1000000);
            this.id = timestamp * 1000 + random;
        }
        return this.id;
    }

    // Getters and setters

    public Long getId() {
        // Ensure ID is generated when accessing
        if (this.id == null) {
            this.id = generateId();
        }
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getAgentName() {
        return agentName;
    }

    public void setAgentName(String agentName) {
        this.agentName = agentName;
    }

    public String getAgentDescription() {
        return agentDescription;
    }

    public void setAgentDescription(String agentDescription) {
        this.agentDescription = agentDescription;
    }

    public LocalDateTime getStartTime() {
        return startTime;
    }

    public void setStartTime(LocalDateTime startTime) {
        this.startTime = startTime;
    }

    public LocalDateTime getEndTime() {
        return endTime;
    }

    public void setEndTime(LocalDateTime endTime) {
        this.endTime = endTime;
    }

    public int getMaxSteps() {
        return maxSteps;
    }

    public void setMaxSteps(int maxSteps) {
        this.maxSteps = maxSteps;
    }

    public int getCurrentStep() {
        return currentStep;
    }

    public void setCurrentStep(int currentStep) {
        this.currentStep = currentStep;
    }

    public ExecutionStatus getStatus() {
        return status;
    }

    public void setStatus(ExecutionStatus status) {
        this.status = status;
    }

    public List<ThinkActRecord> getThinkActSteps() {
        return thinkActSteps;
    }

    public void setThinkActSteps(List<ThinkActRecord> thinkActSteps) {
        this.thinkActSteps = thinkActSteps;
        this.currentStep = thinkActSteps != null ? thinkActSteps.size() : 0;
    }

    public String getAgentRequest() {
        return agentRequest;
    }

    public void setAgentRequest(String agentRequest) {
        this.agentRequest = agentRequest;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public String getModelName() {
        return modelName;
    }

    public void setModelName(String modelName) {
        this.modelName = modelName;
    }

    @Override
    public String toString() {
        return "AgentExecutionRecord{" + "id='" + id + '\'' + ", conversationId='" + conversationId + '\''
            + ", agentName='" + agentName + '\'' + ", status='" + status + '\'' + ", currentStep=" + currentStep
            + ", maxSteps=" + maxSteps + ", stepsCount=" + (thinkActSteps != null ? thinkActSteps.size() : 0) + '}';
    }

    /**
     * Save record to persistent storage. Empty implementation, to be overridden by specific storage implementations.
     * Also recursively saves all ThinkActRecords
     * 
     * @return Record ID after saving
     */
    public Long save() {
        // If ID is null, generate a random ID
        if (this.id == null) {
            // Use combination of timestamp and random number to generate ID
            long timestamp = System.currentTimeMillis();
            int random = (int) (Math.random() * 1000000);
            this.id = timestamp * 1000 + random;
        }

        // Save all ThinkActRecords
        if (thinkActSteps != null) {
            for (ThinkActRecord thinkActRecord : thinkActSteps) {
                thinkActRecord.save();
            }
        }
        return this.id;
    }

    public String getConversationId() {
        return conversationId;
    }

    public void setConversationId(String conversationId) {
        this.conversationId = conversationId;
    }
}
