package tech.easyflow.admin.controller.ai;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.util.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import tech.easyflow.admin.controller.ai.support.AiResourceCreatorNameSupport;
import tech.easyflow.admin.model.ai.WorkflowDesignerOptionsView;
import tech.easyflow.admin.service.ai.WorkflowDesignerOptionService;
import tech.easyflow.agent.entity.AgentToolBinding;
import tech.easyflow.agent.enums.AgentToolType;
import tech.easyflow.agent.service.AgentToolBindingService;
import tech.easyflow.ai.permission.WorkflowShareResourceAccessGrantProvider;
import tech.easyflow.ai.permission.WorkflowVisibilityQueryHelper;
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckResult;
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
import tech.easyflow.ai.easyagentsflow.service.CodeEngineCapabilityService;
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
import tech.easyflow.ai.easyagentsflow.service.WorkflowDatacenterContentService;
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.publish.WorkflowPublishAppService;
import tech.easyflow.ai.service.AiResourceApprovalStateService;
import tech.easyflow.ai.vo.OfflineImpactCheckVo;
import tech.easyflow.approval.entity.vo.ApprovalActionResult;
import tech.easyflow.ai.service.ModelService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.constant.Constants;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount;
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 tech.easyflow.datacenter.execution.model.DatasetRef;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.enums.ResourceLookup;
import tech.easyflow.system.enums.VisibilityScope;
import tech.easyflow.system.permission.resource.RequireResourceAccess;
import tech.easyflow.system.service.ResourceAccessService;
import tech.easyflow.system.service.SysApiKeyService;

import javax.annotation.Resource;
import java.io.InputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 控制层。
 *
 * @author michael
 * @since 2024-08-23
 */
@RestController
@RequestMapping("/api/v1/workflow")
public class WorkflowController extends BaseCurdController<WorkflowService, Workflow> {
    private final ModelService modelService;

    @Resource
    private SysApiKeyService apiKeyService;
    @Resource
    private AgentToolBindingService agentToolBindingService;
    @Resource
    private ChainExecutor chainExecutor;
    @Resource
    private TinyFlowService tinyFlowService;
    @Resource
    private CodeEngineCapabilityService codeEngineCapabilityService;
    @Resource
    private WorkflowCheckService workflowCheckService;
    @Resource
    private WorkflowDatacenterContentService workflowDatacenterContentService;
    @Resource
    private WorkflowRunningParameterResolver workflowRunningParameterResolver;
    @Resource
    private ResourceAccessService resourceAccessService;
    @Resource
    private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
    @Resource
    private WorkflowPublishAppService workflowPublishAppService;
    @Resource
    private AiResourceApprovalStateService aiResourceApprovalStateService;
    @Resource
    private AiResourceCreatorNameSupport aiResourceCreatorNameSupport;
    @Resource
    private WorkflowShareResourceAccessGrantProvider workflowShareGrantProvider;
    @Resource
    private WorkflowDesignerOptionService workflowDesignerOptionService;

    public WorkflowController(WorkflowService service, ModelService modelService) {
        super(service);
        this.modelService = modelService;
    }

    /**
     * 获取工作流列表关键字搜索字段。
     *
     * @return 标题和描述属性
     */
    @Override
    protected String[] getKeywordSearchProperties() {
        return new String[]{"title", "description"};
    }

    /**
     * 查询工作流设计器初始化所需的安全选项。
     *
     * @return 模型、知识库和代码引擎选项
     */
    @GetMapping("/designer/options")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<WorkflowDesignerOptionsView> designerOptions() {
        return Result.ok(workflowDesignerOptionService.listOptions(
                codeEngineCapabilityService.listSupportedCodeEngines()));
    }

    /**
     * 分页查询工作流设计器可用插件。
     *
     * @param pageNumber 页码
     * @param pageSize 每页数量
     * @param keyword 插件名称或描述关键字
     * @return 插件安全选项分页
     */
    @GetMapping("/designer/plugins")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<Page<WorkflowDesignerOptionsView.PluginOption>> designerPlugins(
            Long pageNumber,
            Long pageSize,
            String keyword) {
        return Result.ok(workflowDesignerOptionService.pagePlugins(pageNumber, pageSize, keyword));
    }

    /**
     * 查询工作流插件节点配置。
     *
     * @param id 插件工具 ID
     * @return 插件节点配置
     */
    @GetMapping("/designer/pluginTinyFlow")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<?> designerPluginTinyFlow(BigInteger id) {
        return Result.ok(workflowDesignerOptionService.getPluginTinyFlowData(id));
    }

    /**
     * 查询工作流设计器的子流程节点配置。
     *
     * @param currentId 当前工作流 ID
     * @param workflowId 子流程 ID
     * @return 子流程输入输出定义
     */
    @GetMapping("/designer/childWorkflow")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<JSONObject> designerChildWorkflow(BigInteger currentId, BigInteger workflowId) {
        return Result.ok(workflowDesignerOptionService.getChildWorkflowNodeData(currentId, workflowId));
    }

    /**
     * 查询工作流数据节点可见的数据源。
     *
     * @return 数据源安全选项
     */
    @GetMapping("/designer/dataSources")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<List<WorkflowDesignerOptionsView.DataSourceOption>> designerDataSources() {
        return Result.ok(workflowDesignerOptionService.listDataSources());
    }

    /**
     * 查询工作流数据节点的数据目录。
     *
     * @param sourceId 数据源 ID
     * @return 目录安全选项
     */
    @GetMapping("/designer/catalogs")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<List<WorkflowDesignerOptionsView.CatalogOption>> designerCatalogs(BigInteger sourceId) {
        return Result.ok(workflowDesignerOptionService.listCatalogs(sourceId));
    }

    /**
     * 查询工作流数据节点的已接入数据集。
     *
     * @param sourceId 数据源 ID
     * @param catalogId 目录 ID
     * @return 数据集安全选项
     */
    @GetMapping("/designer/managedTables")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<List<WorkflowDesignerOptionsView.DatasetOption>> designerManagedTables(
            BigInteger sourceId,
            BigInteger catalogId) {
        return Result.ok(workflowDesignerOptionService.listManagedDatasets(sourceId, catalogId));
    }

    /**
     * 查询工作流数据节点的数据集结构。
     *
     * @param datasetRef 数据集引用
     * @return 数据集结构安全视图
     */
    @GetMapping("/designer/schema")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<WorkflowDesignerOptionsView.DatasetSchemaOption> designerSchema(DatasetRef datasetRef) {
        return Result.ok(workflowDesignerOptionService.getDatasetSchema(datasetRef));
    }

    /**
     * 节点单独运行
     */
    @PostMapping("/singleRun")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.USE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#workflowId",
            denyMessage = "无权限运行工作流"
    )
    public Result<?> singleRun(
            @JsonBody(value = "workflowId", required = true) BigInteger workflowId,
            @JsonBody(value = "nodeId", required = true) String nodeId,
            @JsonBody("variables") Map<String, Object> variables) {

        Workflow workflow = service.getById(workflowId);
        if (workflow == null) {
            return Result.fail(1, "工作流不存在");
        }
        workflowCheckService.checkOrThrow(
                workflow.getContent(), WorkflowCheckStage.PRE_EXECUTE, workflow.getId());
        workflowDesignerOptionService.assertContentReferences(workflow.getContent());
        if (variables == null) {
            variables = new HashMap<>();
        }
        variables = workflowRunningParameterResolver.normalizeRuntimeVariables(workflow.getContent(), variables);
        if (StpUtil.isLogin()) {
            variables.put(Constants.LOGIN_USER_KEY, SaTokenUtil.getLoginAccount());
        }
        Map<String, Object> res = chainExecutor.executeNode(workflowId.toString(), nodeId, variables);
        return Result.ok(res);
    }

    /**
     * 运行工作流 - v2
     */
    @PostMapping("/runAsync")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.USE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限运行工作流"
    )
    public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
                                   @JsonBody("variables") Map<String, Object> variables) {
        if (variables == null) {
            variables = new HashMap<>();
        }
        Workflow workflow = service.getById(id);
        if (workflow == null) {
            throw new RuntimeException("工作流不存在");
        }
        workflowCheckService.checkOrThrow(workflow.getContent(), WorkflowCheckStage.PRE_EXECUTE, workflow.getId());
        workflowDesignerOptionService.assertContentReferences(workflow.getContent());
        variables = workflowRunningParameterResolver.normalizeRuntimeVariables(workflow.getContent(), variables);
        if (StpUtil.isLogin()) {
            variables.put(Constants.LOGIN_USER_KEY, SaTokenUtil.getLoginAccount());
        }
        String executeId = chainExecutor.executeAsync(id.toString(), variables);
        return Result.ok(executeId);
    }

    /**
     * 获取工作流运行状态 - v2
     */
    @PostMapping("/getChainStatus")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.USE,
            lookup = ResourceLookup.EXEC_KEY,
            idExpr = "#executeId",
            denyMessage = "无权限访问该执行记录"
    )
    public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
                                            @JsonBody("nodes") List<NodeInfo> nodes) {
        ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
        return Result.ok(res);
    }

    /**
     * 恢复工作流运行 - v2
     */
    @PostMapping("/resume")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.USE,
            lookup = ResourceLookup.EXEC_KEY,
            idExpr = "#executeId",
            denyMessage = "无权限恢复工作流执行"
    )
    public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
                               @JsonBody("confirmParams") Map<String, Object> confirmParams) {
        if (!chainExecutor.resumeAsyncIfSuspended(executeId, confirmParams)) {
            throw new BusinessException(
                    409,
                    40901,
                    "当前执行状态不可恢复，仅暂停中的工作流允许恢复");
        }
        return Result.ok();
    }

    @PostMapping("/importWorkFlow")
    @SaCheckPermission("/api/v1/workflow/save")
    public Result<Void> importWorkFlow(Workflow workflow, MultipartFile jsonFile) throws Exception {
        if (workflow.getId() != null) {
            Workflow sourceWorkflow = requireWorkflow(String.valueOf(workflow.getId()));
            resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, sourceWorkflow, ResourceAction.MANAGE, "无权限管理工作流");
        }
        InputStream is = jsonFile.getInputStream();
        String content = IoUtil.read(is, StandardCharsets.UTF_8);
        workflow.setContent(content);
        workflowCheckService.checkOrThrow(content, WorkflowCheckStage.SAVE, workflow.getId());
        save(workflow);
        return Result.ok();
    }

    @GetMapping("/exportWorkFlow")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.READ,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限访问工作流"
    )
    public Result<String> exportWorkFlow(BigInteger id) {
        Workflow workflow = service.getById(id);
        if (workflow == null) {
            throw new BusinessException("工作流不存在");
        }
        return Result.ok("", workflow.getContent());
    }

    @GetMapping("getRunningParameters")
    @SaCheckPermission("/api/v1/workflow/query")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.READ,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限访问工作流"
    )
    public Result<?> getRunningParameters(@RequestParam BigInteger id) {
        Workflow workflow = service.getById(id);

        if (workflow == null) {
            return Result.fail(1, "can not find the workflow by id: " + id);
        }
        workflowCheckService.checkOrThrow(workflow.getContent(), WorkflowCheckStage.PRE_EXECUTE, workflow.getId());
        workflowDesignerOptionService.assertContentReferences(workflow.getContent());
        Map<String, Object> res = workflowRunningParameterResolver.buildRunningParametersView(workflow);
        if (res == null) {
            return Result.fail(2, "节点配置错误，请检查! ");
        }
        return Result.ok(res);
    }

    /**
     * 提交发布审批。
     *
     * @param id 工作流 ID
     * @param applicationReason 审批说明
     * @return 审批实例 ID
     */
    @PostMapping("/submitPublishApproval")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限发布工作流"
    )
    public Result<BigInteger> submitPublishApproval(
            @JsonBody("id") BigInteger id,
            @JsonBody("applicationReason") String applicationReason
    ) {
        return buildApprovalActionResult(
                workflowPublishAppService.submitPublishApproval(id, applicationReason),
                "已提交发布审批",
                "已直接发布"
        );
    }

    /**
     * 预检工作流发布是否命中审批流。
     *
     * @param id 工作流 ID
     * @return 是否需要审批
     */
    @GetMapping("/publishApprovalRequirement")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限发布工作流"
    )
    public Result<Boolean> publishApprovalRequirement(@RequestParam BigInteger id) {
        return Result.ok(workflowPublishAppService.isPublishApprovalRequired(id));
    }

    /**
     * 提交下线审批。
     *
     * @param id 工作流 ID
     * @return 审批实例 ID
     */
    @PostMapping("/submitOfflineApproval")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限下线工作流"
    )
    public Result<BigInteger> submitOfflineApproval(@JsonBody("id") BigInteger id) {
        return buildApprovalActionResult(
                workflowPublishAppService.submitOfflineApproval(id),
                "已提交下线审批",
                "已直接下线"
        );
    }

    /**
     * 检查工作流下线影响。
     *
     * @param id 工作流 ID
     * @return 下线影响结果
     */
    @GetMapping("/offlineImpactCheck")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限管理工作流"
    )
    public Result<OfflineImpactCheckVo> offlineImpactCheck(@RequestParam BigInteger id) {
        return Result.ok(workflowPublishAppService.checkOfflineImpact(id));
    }

    /**
     * 提交删除审批。
     *
     * @param id 工作流 ID
     * @return 审批实例 ID
     */
    @PostMapping("/submitDeleteApproval")
    @SaCheckPermission("/api/v1/workflow/remove")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限删除工作流"
    )
    public Result<BigInteger> submitDeleteApproval(@JsonBody("id") BigInteger id) {
        return buildApprovalActionResult(
                workflowPublishAppService.submitDeleteApproval(id),
                "已提交删除审批",
                "已直接删除"
        );
    }

    @GetMapping("/supportedCodeEngines")
    @SaCheckPermission("/api/v1/workflow/query")
    public Result<?> supportedCodeEngines() {
        return Result.ok(codeEngineCapabilityService.listSupportedCodeEngines());
    }

    @PostMapping("/check")
    @SaCheckPermission("/api/v1/workflow/save")
    public Result<WorkflowCheckResult> check(@JsonBody("id") BigInteger id,
                                             @JsonBody("content") String content,
                                             @JsonBody(value = "stage", required = true) String stage) {
        if (id != null) {
            Workflow workflow = requireWorkflow(String.valueOf(id));
            resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.MANAGE, "无权限管理工作流");
        }
        WorkflowCheckStage checkStage = WorkflowCheckStage.from(stage);
        WorkflowCheckResult checkResult;
        if (StringUtils.hasLength(content)) {
            checkResult = workflowCheckService.checkContent(content, checkStage, id);
        } else if (id != null) {
            checkResult = workflowCheckService.checkWorkflow(id, checkStage);
        } else {
            throw new BusinessException("id 与 content 不能同时为空");
        }
        return Result.ok(checkResult);
    }

    @Override
    @GetMapping("detail")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.READ,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限访问工作流"
    )
    public Result<Workflow> detail(String id) {
        Workflow workflow = service.getDetail(id);
        aiResourceApprovalStateService.fillWorkflowApprovalState(workflow);
        return Result.ok(workflow);
    }

    @GetMapping("/copy")
    @SaCheckPermission("/api/v1/workflow/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.WORKFLOW,
            action = ResourceAction.READ,
            lookup = ResourceLookup.WORKFLOW_ID,
            idExpr = "#id",
            denyMessage = "无权限访问工作流"
    )
    public Result<Void> copy(BigInteger id) {
        LoginAccount account = SaTokenUtil.getLoginAccount();
        Workflow workflow = service.getById(id);
        if (workflow == null) {
            throw new BusinessException("工作流不存在");
        }
        workflow.setId(null);
        workflow.setAlias(IdUtil.fastSimpleUUID());
        workflow.setRevision(0);
        commonFiled(workflow, account.getId(), account.getTenantId(), account.getDeptId());
        workflowDesignerOptionService.assertContentReferences(workflow.getContent());
        service.save(workflow);
        return Result.ok();
    }

    /**
     * 更新工作流；分享访问只允许按修订号更新设计内容。
     *
     * @param entity 工作流更新内容
     * @return 更新结果
     */
    @Override
    @PostMapping("update")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> update(@JsonBody Workflow entity) {
        if (entity == null || entity.getId() == null) {
            throw new BusinessException("工作流 ID 不能为空");
        }
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        boolean sharedRequest = workflowShareGrantProvider.isSharedRequestFor(
                entity.getId(),
                loginAccount
        );
        if (sharedRequest && entity.getContent() == null) {
            throw new BusinessException(403, 403, "分享链接仅允许编辑工作流内容");
        }
        if (entity.getContent() == null) {
            return super.update(entity);
        }
        if (entity.getRevision() == null) {
            throw workflowRevisionConflict();
        }
        Result<?> beforeResult = onSaveOrUpdateBefore(entity, false);
        if (beforeResult != null) {
            return beforeResult;
        }
        boolean updated = service.updateContentByRevision(
                entity.getId(),
                entity.getContent(),
                entity.getRevision(),
                new Date(),
                loginAccount.getId()
        );
        if (!updated) {
            throw workflowRevisionConflict();
        }
        entity.setRevision(entity.getRevision() + 1);
        if (!sharedRequest) {
            entity.setContent(null);
            service.updateById(entity);
        }
        onSaveOrUpdateAfter(entity, false);
        return Result.ok(Map.of("revision", entity.getRevision()));
    }

    @Override
    protected Result onSaveOrUpdateBefore(Workflow entity, boolean isSave) {
        normalizeVisibilityScope(entity, isSave);
        if (isSave && entity.getRevision() == null) {
            entity.setRevision(0);
        }
        if (!isSave && entity.getId() != null) {
            Workflow existed = requireWorkflow(String.valueOf(entity.getId()));
            resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, existed, ResourceAction.MANAGE, "无权限管理工作流");
        }
        if (StringUtils.hasLength(entity.getContent())) {
            workflowCheckService.checkOrThrow(entity.getContent(), WorkflowCheckStage.SAVE, entity.getId());
            workflowDesignerOptionService.assertContentReferences(entity.getContent());
        }

        String alias = entity.getAlias();
        if (StringUtils.hasLength(alias)) {
            Workflow workflow = service.getByAlias(alias);
            if (workflow == null) {
                return null;
            }
            if (isSave) {
                throw new BusinessException("别名已存在！");
            }
            BigInteger id = entity.getId();
            if (id.compareTo(workflow.getId()) != 0) {
                throw new BusinessException("别名已存在！");
            }
        } else {
            entity.setAlias(null);
        }
        return null;
    }

    @Override
    public Result<List<Workflow>> list(Workflow entity, Boolean asTree, String sortKey, String sortType) {
        QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
        workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
        applyPublishedOnlyFilter(queryWrapper);
        queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
        List<Workflow> workflows = service.list(queryWrapper);
        aiResourceApprovalStateService.fillWorkflowApprovalState(workflows);
        return Result.ok(workflows);
    }

    @Override
    protected Page<Workflow> queryPage(Page<Workflow> page, QueryWrapper queryWrapper) {
        workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
        applyPublishedOnlyFilter(queryWrapper);
        Page<Workflow> result = super.queryPage(page, queryWrapper);
        aiResourceApprovalStateService.fillWorkflowApprovalState(result.getRecords());
        aiResourceCreatorNameSupport.fillWorkflowCreatorNames(result.getRecords());
        return result;
    }

    @Override
    @PostMapping("remove")
    public Result<?> remove(@JsonBody(value = "id", required = true) Serializable id) {
        return Result.fail(1, "请使用发布状态操作删除工作流");
    }

    private Result<BigInteger> buildApprovalActionResult(ApprovalActionResult actionResult,
                                                         String approvalMessage,
                                                         String directMessage) {
        return Result.ok(
                actionResult.isApprovalRequired() ? approvalMessage : directMessage,
                actionResult.getInstanceId()
        );
    }

    @Override
    protected Result onRemoveBefore(Collection<Serializable> ids) {
        for (Serializable id : ids) {
            Workflow workflow = requireWorkflow(String.valueOf(id));
            resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.MANAGE, "无权限管理工作流");
        }
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq(AgentToolBinding::getToolType, AgentToolType.WORKFLOW.name())
                .in(AgentToolBinding::getTargetId, ids);
        boolean exists = agentToolBindingService.exists(queryWrapper);
        if (exists) {
            return Result.fail(1, "此工作流仍被智能体使用，请先取消绑定后再删除");
        }
        return null;
    }

    private void normalizeVisibilityScope(Workflow entity, boolean isSave) {
        if (entity == null) {
            return;
        }
        if (!StringUtils.hasLength(entity.getVisibilityScope())) {
            if (isSave) {
                entity.setVisibilityScope(VisibilityScope.PRIVATE.name());
            }
            return;
        }
        entity.setVisibilityScope(VisibilityScope.from(entity.getVisibilityScope()).name());
    }

    private Workflow requireWorkflow(String idOrAlias) {
        Workflow workflow = service.getDetail(idOrAlias);
        if (workflow == null) {
            throw new BusinessException("工作流不存在");
        }
        return workflow;
    }

    /**
     * 构建工作流内容修订冲突异常。
     *
     * @return HTTP 409 业务异常
     */
    private BusinessException workflowRevisionConflict() {
        return new BusinessException(409, 409, "工作流已被其他人更新，请刷新后重新编辑");
    }

    private void applyPublishedOnlyFilter(QueryWrapper queryWrapper) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        String publishedOnly = attributes.getRequest().getParameter("publishedOnly");
        if ("true".equalsIgnoreCase(publishedOnly)) {
            queryWrapper.eq("publish_status", PublishStatus.PUBLISHED.getCode());
        }
    }
}
