package com.infoepoch.pms.agent.platform.agent.domain;

import com.infoepoch.pms.agent.common.utils.SnowFlake;
import com.infoepoch.pms.agent.platform.model.domain.AiModelConfig;
import com.infoepoch.pms.agent.platform.shared.exception.BusinessException;
import com.infoepoch.pms.agent.platform.shared.response.ResultCode;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;

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

/**
 * 智能体实体。
 * <p>
 * 代表一类业务表单处理流程（如请假、报销等），包含 AI 系统提示词、
 * 动态字段定义和提交目标 URL。每个智能体通过 Tool Calling 被主 ReactAgent 触发。
 * </p>
 */
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Agent {

    /**
     * 智能体名称最大长度。
     */
    private static final int NAME_MAX_LENGTH = 100;
    /**
     * 提交 URL 最大长度。
     */
    private static final int SUBMIT_URL_MAX_LENGTH = 500;

    private String id;

    /**
     * 智能体名称，如"请假申请"。
     */
    private String name;

    /**
     * 智能体描述，用于 Tool Calling 时大模型识别意图。
     */
    private String description;

    /**
     * 系统提示词，注入到子 ReactAgent 的 system message，可选。
     */
    private String systemPrompt;

    /**
     * 表单提交目标 URL，可选，留空时使用打桩日志提交。
     */
    private String submitUrl;

    /**
     * 该智能体使用的模型配置，可选，为 null 时使用全局默认模型。
     */
    private AiModelConfig modelConfig;

    /**
     * 该智能体使用的模型配置id
     */
    private String modelConfigId;

    /**
     * 是否启用。禁用后主 ReactAgent 不会加载此智能体。
     */
    private boolean enabled = true;

    /**
     * 记录创建时间。
     */
    private LocalDateTime createdAt;

    /**
     * 记录最后更新时间。
     */
    private LocalDateTime updatedAt;

    /**
     * 上下文窗口大小。0 表示不限制，正整数表示发给 LLM 的最大消息条数。
     */
    private int contextWindowSize = 0;

    /**
     * 智能体的动态字段列表，按 sortOrder 升序排列。
     */
    private List<AgentField> fields = new ArrayList<>();

    /**
     * 仓储还原
     */
    public Agent(String id, String name, String description, String systemPrompt, String submitUrl, String modelConfigId, boolean enabled, LocalDateTime createdAt, LocalDateTime updatedAt, int contextWindowSize) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.systemPrompt = systemPrompt;
        this.submitUrl = submitUrl;
        this.modelConfigId = modelConfigId;
        this.enabled = enabled;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
        this.contextWindowSize = contextWindowSize;
    }

    /**
     * 创建智能体。
     *
     * @param name              智能体名称，必填，最长 100 字符
     * @param description       描述（用于 Tool Calling 意图识别），必填
     * @param systemPrompt      系统提示词，可选
     * @param submitUrl         提交目标 URL，可选，最长 500 字符
     * @param modelConfig       指定模型配置，可选，为 null 使用全局默认
     * @param contextWindowSize 上下文窗口大小，0 表示不限制，不能为负数
     */
    public Agent(String name, String description, String systemPrompt,
                 String submitUrl, AiModelConfig modelConfig, int contextWindowSize) {
        LocalDateTime now = LocalDateTime.now();
        this.id = SnowFlake.instant().nextId().toString();
        this.name = normalizeName(name);
        this.description = normalizeDescription(description);
        this.systemPrompt = systemPrompt == null ? null : systemPrompt.trim();
        this.submitUrl = normalizeOptional(submitUrl, SUBMIT_URL_MAX_LENGTH, "提交 URL");
        this.modelConfig = modelConfig;
        this.modelConfigId = modelConfig == null ? null : modelConfig.getId();
        this.contextWindowSize = normalizeContextWindowSize(contextWindowSize);
        this.createdAt = now;
        this.updatedAt = now;
    }

    public static Agent restore(String id,
                                String name,
                                String description,
                                String systemPrompt,
                                String submitUrl,
                                AiModelConfig modelConfig,
                                boolean enabled,
                                LocalDateTime createdAt,
                                LocalDateTime updatedAt,
                                int contextWindowSize,
                                List<AgentField> fields) {
        Agent agent = new Agent();
        agent.id = id;
        agent.name = name;
        agent.description = description;
        agent.systemPrompt = systemPrompt;
        agent.submitUrl = submitUrl;
        agent.modelConfig = modelConfig;
        agent.modelConfigId = modelConfig == null ? null : modelConfig.getId();
        agent.enabled = enabled;
        agent.createdAt = createdAt;
        agent.updatedAt = updatedAt;
        agent.contextWindowSize = contextWindowSize;
        agent.fields = fields == null ? new ArrayList<>() : new ArrayList<>(fields);
        return agent;
    }

    public void replaceFields(List<AgentField> fields) {
        this.fields = fields == null ? new ArrayList<>() : new ArrayList<>(fields);
    }

    public void setModelConfig(AiModelConfig modelConfig) {
        this.modelConfig = modelConfig;
        this.modelConfigId = modelConfig == null ? null : modelConfig.getId();
    }

    /**
     * 修改智能体配置。
     *
     * @param name              新名称，必填，最长 100 字符
     * @param description       新描述，必填
     * @param systemPrompt      新系统提示词，可选
     * @param submitUrl         新提交 URL，可选，最长 500 字符
     * @param modelConfig       新模型配置，可选，传 null 则清空（使用全局默认）
     * @param contextWindowSize 上下文窗口大小，0 表示不限制，不能为负数
     */
    public void modify(String name, String description, String systemPrompt,
                       String submitUrl, AiModelConfig modelConfig, int contextWindowSize) {
        this.name = normalizeName(name);
        this.description = normalizeDescription(description);
        this.systemPrompt = systemPrompt == null ? null : systemPrompt.trim();
        this.submitUrl = normalizeOptional(submitUrl, SUBMIT_URL_MAX_LENGTH, "提交 URL");
        this.modelConfig = modelConfig;
        this.modelConfigId = modelConfig == null ? null : modelConfig.getId();
        this.contextWindowSize = normalizeContextWindowSize(contextWindowSize);
        this.updatedAt = LocalDateTime.now();
    }

    /**
     * 切换启用/禁用状态。
     */
    public void toggleEnabled() {
        this.enabled = !this.enabled;
        this.updatedAt = LocalDateTime.now();
    }

    /**
     * 规范化并校验智能体名称。
     *
     * @param name 原始名称
     * @return 规范化后的名称
     */
    private String normalizeName(String name) {
        if (!StringUtils.hasText(name)) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "智能体名称不能为空");
        }
        String normalized = name.trim();
        if (normalized.length() > NAME_MAX_LENGTH) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    "智能体名称长度不能超过 " + NAME_MAX_LENGTH + " 个字符");
        }
        return normalized;
    }

    /**
     * 规范化并校验智能体描述。
     *
     * @param description 原始描述
     * @return 规范化后的描述
     */
    private String normalizeDescription(String description) {
        if (!StringUtils.hasText(description)) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "智能体描述不能为空");
        }
        return description.trim();
    }

    /**
     * 规范化并校验可选字符串字段。
     *
     * @param value     原始值
     * @param maxLength 最大长度
     * @param fieldName 字段名（用于异常提示）
     * @return 规范化结果，空字符串归一化为 null
     */
    private String normalizeOptional(String value, int maxLength, String fieldName) {
        if (value == null) {
            return null;
        }
        String normalized = value.trim();
        if (normalized.length() > maxLength) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    fieldName + " 长度不能超过 " + maxLength + " 个字符");
        }
        return normalized.isEmpty() ? null : normalized;
    }

    /**
     * 校验上下文窗口大小。
     *
     * @param value 原始窗口大小
     * @return 校验后的窗口大小
     */
    private int normalizeContextWindowSize(int value) {
        if (value < 0) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "上下文窗口大小不能为负数");
        }
        return value;
    }
}
