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

import com.alibaba.fastjson.JSON;
import com.infoepoch.pms.agent.common.utils.SnowFlake;
import com.infoepoch.pms.agent.platform.agent.domain.Agent;
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.NoArgsConstructor;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 聊天机器人实体。
 */
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Chatbot {

    /** 聊天机器人名称最大长度。 */
    private static final int NAME_MAX_LENGTH = 100;
    /** 聊天机器人描述最大长度。 */
    private static final int DESCRIPTION_MAX_LENGTH = 500;

    private String id;

    /** 聊天机器人名称，必填，系统内唯一。 */
    private String name;

    /** 聊天机器人描述，可选，最长 500 字符。 */
    private String description;

    /** 系统提示词，可选。 */
    private String systemPrompt;

    /** 绑定的模型配置，可选，为 null 时使用系统默认模型。 */
    private AiModelConfig modelConfig;
    /**
     * 绑定的模型配置id
     */
    private String modelConfigId;

    /** 启用的工具标识列表，使用 JSON 数组存储。 */
    private List<String> enabledTools = new ArrayList<>();

    /**
     * 启用的工具标识列表json
     */
    private String enabledToolsJson;

    /** 关联的子智能体集合。 */
    private Set<Agent> subAgents = new LinkedHashSet<>();

    /** 上下文窗口大小。0 表示不限制，不能为负数。 */
    private int contextWindowSize = 20;

    /** 是否启用。 */
    private boolean enabled = true;

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

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


    /**
     * 获取聊天机器人主键。
     *
     * @return 聊天机器人主键
     */
    public String getId() {
        return id;
    }

    /**
     * 获取聊天机器人名称。
     *
     * @return 聊天机器人名称
     */
    public String getName() {
        return name;
    }

    /**
     * 获取聊天机器人描述。
     *
     * @return 聊天机器人描述
     */
    public String getDescription() {
        return description;
    }

    /**
     * 获取系统提示词。
     *
     * @return 系统提示词
     */
    public String getSystemPrompt() {
        return systemPrompt;
    }

    /**
     * 获取绑定的模型配置。
     *
     * @return 模型配置
     */
    public AiModelConfig getModelConfig() {
        return modelConfig;
    }

    public String getModelConfigId() {
        return modelConfigId;
    }

    /**
     * 获取启用的工具列表只读副本。
     *
     * @return 启用工具列表只读副本
     */
    public List<String> getEnabledTools() {
        return List.copyOf(enabledTools);
    }

    /**
     * 获取子智能体集合只读副本。
     *
     * @return 子智能体集合只读副本
     */
    public Set<Agent> getSubAgents() {
        return Collections.unmodifiableSet(new LinkedHashSet<>(subAgents));
    }


    /**
     * 获取上下文窗口大小。
     *
     * @return 上下文窗口大小
     */
    public int getContextWindowSize() {
        return contextWindowSize;
    }

    /**
     * 判断聊天机器人是否启用。
     *
     * @return true 表示启用，false 表示禁用
     */
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * 获取创建时间。
     *
     * @return 创建时间
     */
    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    /**
     * 获取最后更新时间。
     *
     * @return 最后更新时间
     */
    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }

    public String getEnabledToolsJson() {
        return enabledToolsJson;
    }

    public Chatbot(String id, String name, String description, String systemPrompt, String modelConfigId, String enabledToolsJson, int contextWindowSize, boolean enabled, LocalDateTime createdAt, LocalDateTime updatedAt) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.systemPrompt = systemPrompt;
        this.modelConfigId = modelConfigId;
        this.enabledToolsJson = enabledToolsJson;
        this.contextWindowSize = contextWindowSize;
        this.enabled = enabled;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
        //还原enabledTools
        if (StringUtils.hasText(enabledToolsJson)){
            enabledTools = JSON.parseArray(enabledToolsJson, String.class);
        }
    }

    /**
     * 创建聊天机器人。
     *
     * @param name 聊天机器人名称，必填，最长 100 字符
     * @param description 聊天机器人描述，可选
     * @param systemPrompt 系统提示词，可选
     * @param modelConfig 模型配置，可选
     * @param enabledTools 启用工具列表，可选，为 null 时使用空列表
     * @param contextWindowSize 上下文窗口大小，0 表示不限制，不能为负数
     * @param subAgents 子智能体集合，可选，为 null 时使用空集合
     */
    public Chatbot(String name, String description, String systemPrompt,
                   AiModelConfig modelConfig, List<String> enabledTools,
                   int contextWindowSize, Set<Agent> subAgents) {
        LocalDateTime now = LocalDateTime.now();
        this.id = SnowFlake.instant().nextId().toString();
        this.name = normalizeName(name);
        this.description = normalizeDescription(description);
        this.systemPrompt = normalizeOptionalText(systemPrompt);
        this.modelConfig = modelConfig;
        this.modelConfigId = modelConfig == null ? null : modelConfig.getId();
        this.enabledTools = normalizeEnabledTools(enabledTools);
        this.enabledToolsJson = JSON.toJSONString(this.enabledTools);
        this.contextWindowSize = normalizeContextWindowSize(contextWindowSize);
        this.subAgents = normalizeSubAgents(subAgents);
        this.createdAt = now;
        this.updatedAt = now;
    }

    public static Chatbot restore(String id,
                                  String name,
                                  String description,
                                  String systemPrompt,
                                  AiModelConfig modelConfig,
                                  List<String> enabledTools,
                                  int contextWindowSize,
                                  boolean enabled,
                                  LocalDateTime createdAt,
                                  LocalDateTime updatedAt,
                                  Set<Agent> subAgents) {
        Chatbot chatbot = new Chatbot();
        chatbot.id = id;
        chatbot.name = name;
        chatbot.description = description;
        chatbot.systemPrompt = systemPrompt;
        chatbot.modelConfig = modelConfig;
        chatbot.modelConfigId = modelConfig == null ? null : modelConfig.getId();
        chatbot.enabledTools = enabledTools == null ? new ArrayList<>() : new ArrayList<>(enabledTools);
        chatbot.enabledToolsJson = JSON.toJSONString(chatbot.enabledTools);
        chatbot.contextWindowSize = contextWindowSize;
        chatbot.enabled = enabled;
        chatbot.createdAt = createdAt;
        chatbot.updatedAt = updatedAt;
        chatbot.subAgents = subAgents == null ? new LinkedHashSet<>() : new LinkedHashSet<>(subAgents);
        return chatbot;
    }

    public void replaceSubAgents(Set<Agent> subAgents) {
        this.subAgents = normalizeSubAgents(subAgents);
    }

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

    public void setSubAgents(Set<Agent> subAgents) {
        this.subAgents = normalizeSubAgents(subAgents);
    }

    /**
     * 修改聊天机器人配置。
     *
     * @param name 聊天机器人名称，必填，最长 100 字符
     * @param description 聊天机器人描述，可选
     * @param systemPrompt 系统提示词，可选
     * @param modelConfig 模型配置，可选
     * @param enabledTools 启用工具列表，可选，为 null 时使用空列表
     * @param contextWindowSize 上下文窗口大小，0 表示不限制，不能为负数
     * @param subAgents 子智能体集合，可选，为 null 时使用空集合
     */
    public void modify(String name, String description, String systemPrompt,
                       AiModelConfig modelConfig, List<String> enabledTools,
                       int contextWindowSize, Set<Agent> subAgents) {
        this.name = normalizeName(name);
        this.description = normalizeDescription(description);
        this.systemPrompt = normalizeOptionalText(systemPrompt);
        this.modelConfig = modelConfig;
        this.modelConfigId = modelConfig == null ? null : modelConfig.getId();
        this.enabledTools = normalizeEnabledTools(enabledTools);
        this.enabledToolsJson = JSON.toJSONString(this.enabledTools);
        this.contextWindowSize = normalizeContextWindowSize(contextWindowSize);
        this.subAgents = normalizeSubAgents(subAgents);
        this.updatedAt = LocalDateTime.now();
    }

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

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

    /**
     * 规范化可选文本字段。
     *
     * @param value 原始文本
     * @return 去首尾空白后的文本，空值保持 null
     */
    private String normalizeOptionalText(String value) {
        if (value == null) {
            return null;
        }
        return value.trim();
    }

    /**
     * 规范化并校验聊天机器人描述。
     *
     * @param value 原始描述
     * @return 规范化后的描述
     */
    private String normalizeDescription(String value) {
        String normalized = normalizeOptionalText(value);
        if (normalized != null && normalized.length() > DESCRIPTION_MAX_LENGTH) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    "聊天机器人描述长度不能超过 " + DESCRIPTION_MAX_LENGTH + " 个字符");
        }
        return normalized;
    }

    /**
     * 规范化启用工具列表。
     *
     * @param values 原始工具列表
     * @return 规范化后的工具列表
     */
    private List<String> normalizeEnabledTools(List<String> values) {
        if (values == null) {
            return new ArrayList<>();
        }
        List<String> normalized = new ArrayList<>();
        for (String value : values) {
            if (!StringUtils.hasText(value)) {
                throw new BusinessException(ResultCode.PARAM_ERROR, "启用工具标识不能为空");
            }
            normalized.add(value.trim());
        }
        return normalized;
    }

    /**
     * 规范化子智能体集合。
     *
     * @param values 原始子智能体集合
     * @return 排序并去重后的集合
     */
    private Set<Agent> normalizeSubAgents(Set<Agent> values) {
        if (values == null) {
            return new LinkedHashSet<>();
        }
        List<Agent> validatedAgents = new ArrayList<>();
        for (Agent value : values) {
            if (value == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR, "子智能体不能为空");
            }
            if (value.getId() == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR, "子智能体必须是已持久化的智能体");
            }
            validatedAgents.add(value);
        }
        validatedAgents.sort(Comparator.comparing(Agent::getName)
                .thenComparing(Agent::getId));

        LinkedHashSet<Agent> normalized = new LinkedHashSet<>();
        for (Agent value : validatedAgents) {
            normalized.add(value);
        }
        return normalized;
    }

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