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

import com.infoepoch.pms.agent.platform.agent.application.dto.AgentDetailResponse;
import com.infoepoch.pms.agent.platform.agent.application.dto.AgentSummaryResponse;
import com.infoepoch.pms.agent.platform.agent.application.dto.CreateAgentRequest;
import com.infoepoch.pms.agent.platform.agent.application.dto.UpdateAgentRequest;
import com.infoepoch.pms.agent.platform.agent.domain.Agent;
import com.infoepoch.pms.agent.platform.agent.domain.AgentField;
import com.infoepoch.pms.agent.platform.agent.domain.irepository.IAgentFieldRepository;
import com.infoepoch.pms.agent.platform.agent.domain.irepository.IAgentRepository;
import com.infoepoch.pms.agent.platform.chatbot.domain.irepository.IChatbotAgentsRepository;
import com.infoepoch.pms.agent.platform.model.application.ModelQueryService;
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.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 智能体管理服务。
 * <p>
 * 负责智能体的 CRUD 操作，包含名称唯一性校验和可选的模型配置关联。
 * </p>
 */
@Service
@RequiredArgsConstructor
public class AgentService {

    private final IAgentRepository agentRepository;
    private final IAgentFieldRepository agentFieldRepository;
    private final IChatbotAgentsRepository chatbotAgentsRepository;
    private final ModelQueryService modelQueryService;

    /**
     * 创建智能体。
     *
     * @param req 创建请求 DTO
     * @return 智能体摘要响应
     * @throws BusinessException RESOURCE_ALREADY_EXISTS 若名称已存在；MODEL_CONFIG_NOT_FOUND 若模型配置不存在
     */
    @Transactional
    public AgentSummaryResponse create(CreateAgentRequest req) {
        if (agentRepository.existsByName(req.getName())) {
            throw new BusinessException(ResultCode.RESOURCE_ALREADY_EXISTS,
                    "智能体名称 [" + req.getName() + "] 已存在");
        }
        AiModelConfig modelConfig = resolveModelConfig(req.getModelConfigId());
        Agent agent = new Agent(req.getName(), req.getDescription(),
                req.getSystemPrompt(), req.getSubmitUrl(), modelConfig,
                req.getContextWindowSize());
        return new AgentSummaryResponse(agentRepository.save(agent));
    }

    /**
     * 按 ID 查询智能体详情（含字段列表）。
     *
     * @param id 智能体 ID
     * @return 智能体详情响应
     * @throws BusinessException AGENT_NOT_FOUND 若不存在
     */
    @Transactional(readOnly = true)
    public AgentDetailResponse findById(String id) {
        Agent agent = attachRelations(getAgentOrThrow(id));
        List<AgentField> fields = agentFieldRepository.findAllByAgentIdOrderBySortOrderAsc(id);
        fields.forEach(field -> field.setAgent(agent));
        agent.replaceFields(fields);
        return new AgentDetailResponse(agent);
    }

    /**
     * 查询所有智能体，按创建时间倒序排列（不含字段列表）。
     *
     * @return 智能体摘要响应列表
     */
    @Transactional(readOnly = true)
    public List<AgentSummaryResponse> listAll() {
        return agentRepository.findAllByOrderByCreatedAtDesc()
                .stream()
                .map(AgentSummaryResponse::new)
                .toList();
    }

    /**
     * 更新智能体基本信息。
     *
     * @param id  智能体 ID
     * @param req 更新请求 DTO
     * @return 更新后的智能体摘要响应
     * @throws BusinessException AGENT_NOT_FOUND 若不存在；RESOURCE_ALREADY_EXISTS 若名称已被占用
     */
    @Transactional
    public AgentSummaryResponse update(String id, UpdateAgentRequest req) {
        Agent agent = getAgentOrThrow(id);
        if (agentRepository.existsByNameAndIdNot(req.getName(), id)) {
            throw new BusinessException(ResultCode.RESOURCE_ALREADY_EXISTS,
                    "智能体名称 [" + req.getName() + "] 已存在");
        }
        AiModelConfig modelConfig = resolveModelConfig(req.getModelConfigId());
        agent.modify(req.getName(), req.getDescription(),
                req.getSystemPrompt(), req.getSubmitUrl(), modelConfig,
                req.getContextWindowSize());
        return new AgentSummaryResponse(agentRepository.save(agent));
    }

    /**
     * 删除智能体（级联删除其所有字段）。
     *
     * @param id 智能体 ID
     * @throws BusinessException AGENT_NOT_FOUND 若不存在
     */
    @Transactional
    public void delete(String id) {
        Agent agent = getAgentOrThrow(id);
        chatbotAgentsRepository.deleteByAgentId(agent.getId());
        agentFieldRepository.deleteByAgentId(agent.getId());
        agentRepository.delete(agent.getId());
    }

    /**
     * 切换智能体启用/禁用状态。
     *
     * @param id 智能体 ID
     * @return 更新后的智能体摘要响应
     * @throws BusinessException AGENT_NOT_FOUND 若不存在
     */
    @Transactional
    public AgentSummaryResponse toggle(String id) {
        Agent agent = getAgentOrThrow(id);
        agent.toggleEnabled();
        return new AgentSummaryResponse(agentRepository.save(agent));
    }

    /**
     * 按 ID 查询智能体，不存在时抛出业务异常。
     *
     * @param id 智能体 ID
     * @return 智能体实体
     */
    private Agent getAgentOrThrow(String id) {
        return agentRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ResultCode.AGENT_NOT_FOUND,
                        "智能体 ID=" + id + " 不存在"));
    }

    private Agent attachRelations(Agent agent) {
        if (agent == null) {
            return null;
        }
        agent.setModelConfig(resolveModelConfig(agent.getModelConfigId()));
        return agent;
    }

    /**
     * 解析模型配置。
     *
     * @param modelConfigId 模型配置 ID
     * @return 模型配置，传 null 时返回 null
     */
    private AiModelConfig resolveModelConfig(String modelConfigId) {
        AiModelConfig config = modelQueryService.getModelConfigOrNull(modelConfigId);
        if (config != null && !"LLM".equals(config.getModelType())) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    "智能体仅支持引用 LLM 类型模型配置");
        }
        return config;
    }
}
