package tech.easyflow.admin.controller.ai;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
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.snapshot.WorkflowPluginSnapshotResolver;
import tech.easyflow.ai.service.BotPluginService;
import tech.easyflow.ai.service.PluginService;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.constant.Constants;
import tech.easyflow.common.annotation.UsePermission;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.common.web.jsonbody.JsonBody;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  控制层。
 *
 * @author WangGangqiang
 * @since 2025-04-27
 */
@RestController
@RequestMapping("/api/v1/pluginItem")
@UsePermission(moduleName = "/api/v1/plugin")
public class PluginItemController extends BaseCurdController<PluginItemService, PluginItem> {
    public PluginItemController(PluginItemService service) {
        super(service);
    }

    @Resource
    private PluginItemService pluginItemService;

    @Resource
    private BotPluginService botPluginService;
    @Resource
    private PluginService pluginService;
    @Resource
    private WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver;
    @Resource
    private WorkflowService workflowService;
    @Resource
    private ChainExecutor chainExecutor;
    @Resource
    private TinyFlowService tinyFlowService;
    @Resource
    private WorkflowCheckService workflowCheckService;

    @PostMapping("/tool/save")
    @SaCheckPermission("/api/v1/plugin/save")
    public Result<Boolean> savePlugin(@JsonBody PluginItem pluginItem){

        return Result.ok(pluginItemService.savePluginTool(pluginItem));
    }

    // 插件工具修改页面查询
    @PostMapping("/tool/search")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<?> searchPlugin(@JsonBody(value = "aiPluginToolId", required = true) BigInteger aiPluginToolId){
        return pluginItemService.searchPlugin(aiPluginToolId);
    }

    @PostMapping("/toolsList")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<List<PluginItem>> searchPluginToolByPluginId(@JsonBody(value = "pluginId", required = true) BigInteger pluginId,
                                                               @JsonBody(value = "botId", required = false) BigInteger botId){
        return Result.ok(pluginItemService.searchPluginToolByPluginId(pluginId, botId));
    }

    @PostMapping("/tool/update")
    @SaCheckPermission("/api/v1/plugin/save")
    public Result<Boolean> updatePlugin(@JsonBody PluginItem pluginItem){
        return Result.ok(pluginItemService.updatePlugin(pluginItem));
    }

    @PostMapping("/tool/list")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<List<PluginItem>> getPluginToolList(@JsonBody(value = "botId", required = true) BigInteger botId){
        return Result.ok(pluginItemService.getPluginToolList(botId));
    }

    @GetMapping("/getTinyFlowData")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<?> getTinyFlowData(BigInteger id) {
        JSONObject nodeData = new JSONObject();
        PluginItem record = pluginItemService.getById(id);
        if (record == null) {
            return Result.ok(nodeData);
        }
        Plugin plugin = pluginService.getById(record.getPluginId());
        nodeData.put("pluginId", record.getId().toString());
        nodeData.put("pluginName", record.getName());
        if (plugin != null) {
            plugin = pluginService.preparePluginForCurrentUser(plugin);
            nodeData.put("pluginType", plugin.getType());
            nodeData.put("workflowId", plugin.getWorkflowId());
            nodeData.put("workflowTitle", plugin.getWorkflowTitle());
            nodeData.put("available", plugin.getAvailable());
            nodeData.put("reasonCode", plugin.getReasonCode());
            nodeData.put("reasonMessage", plugin.getReasonMessage());
        }

        JSONArray parameters = new JSONArray();
        JSONArray outputDefs = new JSONArray();
        String inputData = record.getInputData();
        if (StrUtil.isNotEmpty(inputData)) {
            JSONArray array = JSON.parseArray(inputData);
            handleArray(array);
            parameters = array;
        }
        String outputData = record.getOutputData();
        if (StrUtil.isNotEmpty(outputData)) {
            JSONArray array = JSON.parseArray(outputData);
            handleArray(array);
            outputDefs = array;
        }
        nodeData.put("schemaHash", resolveSchemaHash(record, plugin));
        nodeData.put("parameters", parameters);
        nodeData.put("outputDefs", outputDefs);
        return Result.ok(nodeData);
    }

    /**
     * 插件试运行接口
     * @return
     */
    @PostMapping("/test")
    public Result<?> pluginToolTest(@JsonBody(value = "inputData", required = true) String inputData,
                                 @JsonBody(value = "pluginToolId", required = true) BigInteger pluginToolId){
        return pluginItemService.pluginToolTest(inputData, pluginToolId);
    }

    /**
     * 工作流插件异步试运行。
     *
     * @param inputData 输入参数 JSON
     * @param pluginToolId 插件工具 ID
     * @return 执行 ID
     */
    @PostMapping("/testAsync")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<String> pluginToolTestAsync(@JsonBody(value = "inputData", required = true) String inputData,
                                              @JsonBody(value = "pluginToolId", required = true) BigInteger pluginToolId) {
        PluginItem pluginItem = pluginItemService.getById(pluginToolId);
        Plugin plugin = requireWorkflowPlugin(pluginItem);
        Plugin preparedPlugin = pluginService.preparePluginForCurrentUser(plugin);
        if (Boolean.FALSE.equals(preparedPlugin.getAvailable())) {
            throw new BusinessException(preparedPlugin.getReasonMessage());
        }
        Workflow workflow = workflowService.getPublishedById(preparedPlugin.getWorkflowId());
        if (workflow == null) {
            throw new BusinessException("未找到已发布工作流");
        }
        workflowCheckService.checkOrThrow(workflow.getContent(), WorkflowCheckStage.PRE_EXECUTE, workflow.getId());
        Map<String, Object> variables = JSON.parseObject(inputData, Map.class);
        if (variables == null) {
            variables = new HashMap<>();
        }
        if (StpUtil.isLogin()) {
            variables.put(Constants.LOGIN_USER_KEY, SaTokenUtil.getLoginAccount());
        }
        String executeId = chainExecutor.executeAsync(
                PublishedWorkflowDefinitionIds.published(String.valueOf(workflow.getId())),
                variables
        );
        return Result.ok(executeId);
    }

    /**
     * 获取工作流插件试运行状态。
     *
     * @param executeId 执行 ID
     * @param nodes 节点列表
     * @return 链路状态
     */
    @PostMapping("/testChainStatus")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<ChainInfo> pluginToolTestChainStatus(@JsonBody(value = "executeId", required = true) String executeId,
                                                       @JsonBody("nodes") List<NodeInfo> nodes) {
        return Result.ok(tinyFlowService.getChainStatus(executeId, nodes));
    }

    /**
     * 恢复工作流插件试运行。
     *
     * @param executeId 执行 ID
     * @param confirmParams 恢复参数
     * @return 空结果
     */
    @PostMapping("/testResume")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<Void> pluginToolTestResume(@JsonBody(value = "executeId", required = true) String executeId,
                                             @JsonBody("confirmParams") Map<String, Object> confirmParams) {
        chainExecutor.resumeAsync(executeId, confirmParams);
        return Result.ok();
    }

    private void handleArray(JSONArray array) {
        for (Object o : array) {
            JSONObject obj = (JSONObject) o;
            obj.put("id", IdUtil.simpleUUID());
            obj.put("nameDisabled", true);
            obj.put("dataTypeDisabled", true);
            obj.put("deleteDisabled", true);
            obj.put("addChildDisabled", true);
            JSONArray children = obj.getJSONArray("children");
            if (children != null) {
                handleArray(children);
            }
        }
    }

    private String resolveSchemaHash(PluginItem record, Plugin plugin) {
        if (record == null) {
            return null;
        }
        if (StrUtil.isNotBlank(record.getSchemaHash())) {
            return record.getSchemaHash();
        }
        if (plugin == null || !PluginType.isWorkflow(plugin.getType()) || plugin.getWorkflowId() == null) {
            return null;
        }
        tech.easyflow.ai.entity.Workflow workflow = workflowService.getPublishedById(plugin.getWorkflowId());
        if (workflow == null) {
            return null;
        }
        return workflowPluginSnapshotResolver.resolveSchemaHash(workflow);
    }

    private Plugin requireWorkflowPlugin(PluginItem pluginItem) {
        if (pluginItem == null) {
            throw new BusinessException("插件工具不存在");
        }
        Plugin plugin = pluginService.getById(pluginItem.getPluginId());
        if (plugin == null) {
            throw new BusinessException("插件不存在");
        }
        if (!PluginType.isWorkflow(plugin.getType())) {
            throw new BusinessException("当前工具不是工作流插件");
        }
        if (plugin.getWorkflowId() == null) {
            throw new BusinessException("插件未绑定工作流");
        }
        return plugin;
    }

    @Override
    protected Result<?> onRemoveBefore(Collection<Serializable> ids) {

        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.in(BotPlugin::getPluginItemId, ids);

        boolean exists = botPluginService.exists(queryWrapper);
        if (exists){
            return Result.fail(1, "此工具还关联着bot，请先取消关联！");
        }
        if (ids.size() == 1) {
            PluginItem pluginItem = pluginItemService.getById(ids.iterator().next());
            if (pluginItem != null) {
                Plugin plugin = pluginService.getById(pluginItem.getPluginId());
                if (plugin != null && PluginType.isWorkflow(plugin.getType())) {
                    return Result.fail(1, "工作流插件工具由系统自动维护，不支持删除");
                }
            }
        }

        return null;
    }
}
