package tech.easyflow.agent.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.agent.entity.Agent;
import tech.easyflow.agent.entity.AgentToolBinding;
import tech.easyflow.agent.enums.AgentToolType;
import tech.easyflow.agent.mapper.AgentMapper;
import tech.easyflow.agent.mapper.AgentToolBindingMapper;
import tech.easyflow.agent.service.AgentToolBindingService;
import tech.easyflow.ai.entity.Mcp;
import tech.easyflow.ai.entity.PluginItem;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.service.McpService;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.service.ResourceAccessService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * Agent 工具绑定服务实现。
 */
@Service
public class AgentToolBindingServiceImpl extends ServiceImpl<AgentToolBindingMapper, AgentToolBinding>
        implements AgentToolBindingService {

    @Resource
    private AgentMapper agentMapper;
    @Resource
    private WorkflowService workflowService;
    @Resource
    private PluginItemService pluginItemService;
    @Resource
    private McpService mcpService;
    @Resource
    private ResourceAccessService resourceAccessService;

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<AgentToolBinding> replaceBindings(BigInteger agentId, List<AgentToolBinding> bindings) {
        Agent agent = requireAgent(agentId);
        resourceAccessService.assertAccess(CategoryResourceType.AGENT, agent, ResourceAction.MANAGE, "无权限管理该 Agent");
        remove(QueryWrapper.create().where("agent_id = ?", agentId));
        if (bindings == null || bindings.isEmpty()) {
            return Collections.emptyList();
        }
        for (int i = 0; i < bindings.size(); i++) {
            AgentToolBinding binding = bindings.get(i);
            validateBinding(binding);
            applyBindingDefaults(agent, binding, i);
        }
        saveBatch(bindings);
        return listEnabled(agentId);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<AgentToolBinding> listEnabled(BigInteger agentId) {
        return list(QueryWrapper.create()
                .where("agent_id = ?", agentId)
                .and("enabled = ?", true)
                .orderBy("sort_no asc, id asc"));
    }

    private Agent requireAgent(BigInteger agentId) {
        Agent agent = agentMapper.selectOneById(agentId);
        if (agent == null) {
            throw new BusinessException("Agent 不存在");
        }
        return agent;
    }

    private void validateBinding(AgentToolBinding binding) {
        if (binding == null || binding.getTargetId() == null || binding.getToolType() == null) {
            throw new BusinessException("工具绑定参数不完整");
        }
        AgentToolType type = AgentToolType.from(binding.getToolType());
        if (type == AgentToolType.WORKFLOW) {
            Workflow workflow = workflowService.getById(binding.getTargetId());
            if (workflow == null || PublishStatus.from(workflow.getPublishStatus()) != PublishStatus.PUBLISHED) {
                throw new BusinessException("绑定工作流不存在或未发布");
            }
            resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.USE, "无权限绑定该工作流");
            return;
        }
        if (type == AgentToolType.PLUGIN) {
            PluginItem pluginItem = pluginItemService.getById(binding.getTargetId());
            if (pluginItem == null || pluginItem.getStatus() == null || pluginItem.getStatus() != 1) {
                throw new BusinessException("绑定插件不存在或未启用");
            }
            return;
        }
        Mcp mcp = mcpService.getById(binding.getTargetId());
        if (mcp == null || !Boolean.TRUE.equals(mcp.getStatus())) {
            throw new BusinessException("绑定 MCP 不存在或未启用");
        }
    }

    private void applyBindingDefaults(Agent agent, AgentToolBinding binding, int index) {
        LoginAccount account = requireCurrentLoginAccount();
        Date now = new Date();
        binding.setId(null);
        binding.setTenantId(agent.getTenantId());
        binding.setAgentId(agent.getId());
        binding.setEnabled(binding.getEnabled() == null || binding.getEnabled());
        binding.setHitlEnabled(Boolean.TRUE.equals(binding.getHitlEnabled()));
        binding.setSortNo(binding.getSortNo() == null ? index : binding.getSortNo());
        binding.setCreated(now);
        binding.setCreatedBy(account.getId());
        binding.setModified(now);
        binding.setModifiedBy(account.getId());
    }

    private LoginAccount requireCurrentLoginAccount() {
        try {
            return SaTokenUtil.getLoginAccount();
        } catch (Exception e) {
            throw new BusinessException("当前登录状态失效，请重新登录后再试");
        }
    }
}
