package tech.easyflow.ai.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import tech.easyflow.ai.entity.BotPlugin;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.PluginItem;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PluginType;
import tech.easyflow.ai.plugin.workflow.availability.WorkflowPluginAvailabilityDecision;
import tech.easyflow.ai.plugin.workflow.availability.WorkflowPluginAvailabilityService;
import tech.easyflow.ai.plugin.workflow.snapshot.WorkflowPluginSnapshotResolver;
import tech.easyflow.ai.mapper.BotPluginMapper;
import tech.easyflow.ai.mapper.PluginMapper;
import tech.easyflow.ai.mapper.PluginItemMapper;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.constant.Constants;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.common.domain.Result;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;

import static tech.easyflow.ai.entity.table.BotPluginTableDef.BOT_PLUGIN;

/**
 * 服务层实现。
 *
 * @author WangGangqiang
 * @since 2025-04-27
 */
@Service
public class PluginItemServiceImpl extends ServiceImpl<PluginItemMapper, PluginItem> implements PluginItemService {

    @Resource
    private PluginItemMapper pluginItemMapper;

    @Resource
    private PluginMapper pluginMapper;

    @Resource
    private BotPluginMapper botPluginMapper;
    @Resource
    private WorkflowPluginAvailabilityService workflowPluginAvailabilityService;
    @Resource
    private WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver;
    @Resource
    private WorkflowService workflowService;

    @Override
    public boolean savePluginTool(PluginItem pluginItem) {
        Plugin plugin = pluginMapper.selectOneById(pluginItem.getPluginId());
        if (plugin != null && PluginType.isWorkflow(plugin.getType())) {
            throw new BusinessException("工作流插件工具由系统自动维护，不支持手动新增");
        }
        pluginItem.setCreated(new Date());
        pluginItem.setRequestMethod("Post");
        int insert = pluginItemMapper.insert(pluginItem);
        if (insert <= 0) {
            throw new BusinessException("保存失败");
        }
        return true;
    }

    @Override
    public Result<?> searchPlugin(BigInteger aiPluginToolId) {
        //查询当前插件工具
        QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create()
                .select()
                .eq(PluginItem::getId, aiPluginToolId);
        PluginItem pluginItem = pluginItemMapper.selectOneByQuery(queryAiPluginToolWrapper);
        // 查询当前的插件信息
        QueryWrapper queryAiPluginWrapper = QueryWrapper.create()
                .select()
                .eq(Plugin::getId, pluginItem.getPluginId());
        Plugin plugin = pluginMapper.selectOneByQuery(queryAiPluginWrapper);
        plugin = preparePluginForCurrentUser(plugin);
        Map<String, Object> result = new HashMap<>();
        result.put("data", pluginItem);
        result.put("aiPlugin", plugin);
        result.put("workflowSnapshot", buildWorkflowSnapshot(plugin));
        return Result.ok(result);
    }

    @Override
    public boolean updatePlugin(PluginItem pluginItem) {
        Plugin existedPlugin = resolvePluginByPluginItemId(pluginItem.getId());
        if (existedPlugin != null && PluginType.isWorkflow(existedPlugin.getType())) {
            throw new BusinessException("工作流插件工具由系统自动维护，不支持手动修改");
        }
        int update = pluginItemMapper.update(pluginItem);
        if (update <= 0) {
            throw new BusinessException("修改失败");
        }
        return true;
    }

    @Override
    public List<PluginItem> searchPluginToolByPluginId(BigInteger pluginId, BigInteger botId) {
        QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create()
                .select()
                .eq(PluginItem::getPluginId, pluginId);
        List<PluginItem> pluginItems = pluginItemMapper.selectListByQueryAs(queryAiPluginToolWrapper, PluginItem.class);
        // 查询当前bot有哪些插件工具方法
        QueryWrapper queryBotPluginTools = QueryWrapper.create()
                .select()
                .eq(BotPlugin::getBotId, botId);
        List<BigInteger> aiBotPluginToolIds = botPluginMapper.selectListWithRelationsByQueryAs(queryBotPluginTools, BigInteger.class);
        aiBotPluginToolIds.forEach(botPluginTooId -> {
            pluginItems.forEach(item -> {
                if (Objects.equals(botPluginTooId, item.getId())) {
                    item.setJoinBot(true);
                }
            });
        });
        return pluginItems;
    }

    @Override
    public List<PluginItem> getPluginToolList(BigInteger botId) {
        QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create()
                .select(BOT_PLUGIN.PLUGIN_ITEM_ID)
                .from(BOT_PLUGIN)
                .where(BOT_PLUGIN.BOT_ID.eq(botId));
        List<BigInteger> pluginToolIds = botPluginMapper.selectListByQueryAs(queryAiPluginToolWrapper, BigInteger.class);
        if (pluginToolIds == null || pluginToolIds.isEmpty()) {
            return Collections.emptyList();
        }
        // 查询当前bots对应的有哪些pluginTool
        return pluginItemMapper.selectListByIds(pluginToolIds);
    }

    @Override
    public Result<?> pluginToolTest(String inputData, BigInteger pluginToolId) {
        PluginItem pluginItem = pluginItemMapper.selectOneById(pluginToolId);
        if (pluginItem == null) {
            throw new BusinessException("插件工具不存在");
        }
        Plugin plugin = pluginMapper.selectOneById(pluginItem.getPluginId());
        if (plugin == null) {
            throw new BusinessException("插件不存在");
        }
        plugin = preparePluginForCurrentUser(plugin);
        if (PluginType.isWorkflow(plugin.getType())) {
            WorkflowPluginAvailabilityDecision decision = workflowPluginAvailabilityService.evaluateForCurrentUser(plugin);
            if (!decision.isAvailable()) {
                return Result.ok(buildUnavailableResult(decision));
            }
            Workflow workflow = workflowService.getPublishedById(plugin.getWorkflowId());
            if (workflow == null) {
                return Result.ok(buildUnavailableResult(decision));
            }
            Map<String, Object> args = com.alibaba.fastjson2.JSON.parseObject(inputData, Map.class);
            Map<String, Object> variables = new LinkedHashMap<>();
            LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
            if (loginAccount != null) {
                variables.put(Constants.LOGIN_USER_KEY, loginAccount);
            }
            if (args != null && !args.isEmpty()) {
                variables.putAll(args);
            }
            Object result = workflowPluginSnapshotResolver.buildWorkflowTool(workflow).invoke(variables);
            return Result.ok(result);
        }
        tech.easyflow.ai.easyagents.tool.PluginTool pluginTool = new tech.easyflow.ai.easyagents.tool.PluginTool(pluginItem);
        return Result.ok(pluginTool.runPluginTool(null, inputData, pluginToolId));
    }

    @Override
    public List<PluginItem> getByPluginId(String id) {

        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.eq(PluginItem::getPluginId, id);

        return list(queryWrapper);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public PluginItem getSingleByPluginId(BigInteger pluginId) {
        if (pluginId == null) {
            return null;
        }
        QueryWrapper queryWrapper = QueryWrapper.create().eq(PluginItem::getPluginId, pluginId);
        List<PluginItem> items = pluginItemMapper.selectListByQuery(queryWrapper);
        return items == null || items.isEmpty() ? null : items.get(0);
    }

    /**
     * 按当前用户视角补充单个插件的可用性信息。
     *
     * @param plugin 插件
     * @return 已补充可用性信息的插件
     */
    private Plugin preparePluginForCurrentUser(Plugin plugin) {
        if (plugin == null) {
            return null;
        }
        plugin.setType(PluginType.from(plugin.getType()).getCode());
        if (!PluginType.isWorkflow(plugin.getType())) {
            plugin.setAvailable(true);
            plugin.setReasonCode(null);
            plugin.setReasonMessage(null);
            return plugin;
        }
        WorkflowPluginAvailabilityDecision decision = workflowPluginAvailabilityService.evaluateForCurrentUser(plugin);
        plugin.setWorkflowTitle(decision.getWorkflowTitle());
        plugin.setAvailable(decision.isAvailable());
        plugin.setReasonCode(decision.getReasonCode());
        plugin.setReasonMessage(decision.getReasonMessage());
        return plugin;
    }

    private Plugin resolvePluginByPluginItemId(BigInteger pluginItemId) {
        if (pluginItemId == null) {
            return null;
        }
        PluginItem existed = pluginItemMapper.selectOneById(pluginItemId);
        if (existed == null || existed.getPluginId() == null) {
            return null;
        }
        return pluginMapper.selectOneById(existed.getPluginId());
    }

    private Map<String, Object> buildUnavailableResult(WorkflowPluginAvailabilityDecision decision) {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("skipped", true);
        result.put("reasonCode", decision.getReasonCode());
        result.put("reasonMessage", decision.getReasonMessage());
        return result;
    }

    /**
     * 构建工作流插件对应的已发布快照摘要。
     *
     * @param plugin 插件
     * @return 快照摘要，不存在时返回 {@code null}
     */
    private Map<String, Object> buildWorkflowSnapshot(Plugin plugin) {
        if (plugin == null || !PluginType.isWorkflow(plugin.getType()) || plugin.getWorkflowId() == null) {
            return null;
        }
        Workflow workflow = workflowService.getPublishedById(plugin.getWorkflowId());
        if (workflow == null) {
            return null;
        }
        Map<String, Object> snapshot = new LinkedHashMap<>();
        snapshot.put("title", workflow.getTitle());
        snapshot.put("description", workflow.getDescription());
        snapshot.put("content", workflow.getContent());
        return snapshot;
    }

}
