package cn.axzo.workflow.starter.api;

import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration;
import cn.axzo.workflow.common.util.ThreadUtil;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutCallbackDTO;
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutTriggerDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO;
import cn.azxo.framework.common.model.CommonResponse;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotBlank;
import cn.axzo.workflow.common.model.request.form.definition.StartFormSearchDTO;
import cn.axzo.workflow.common.model.request.form.instance.FormDetailDTO;
import cn.axzo.workflow.common.model.request.form.instance.FormSearchDTO;
import cn.axzo.workflow.common.model.response.form.FormVO;
import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO;
import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO;
import java.util.List;
import cn.axzo.workflow.common.model.dto.SignFileDTO;
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
import cn.axzo.workflow.common.model.request.bpmn.log.LogApproveSearchDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BeforeProcessInstanceCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO;
import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO;
import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO;
import cn.axzo.workflow.common.model.response.bpmn.process.ExtProcessLogVO;
import cn.axzo.workflow.common.model.response.bpmn.process.NodesByModelVO;
import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO;
import cn.axzo.workflow.common.model.response.bpmn.process.doc.DocPendingVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PutMapping;
import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;
import java.util.Map;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnNodeBackSystemOperateDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditWithFormDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskResetApproversDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO;
import javax.validation.constraints.NotEmpty;

/**
 * Workflow Engine Starter Core Service
 * <p>
 * 该类是根据 API 动态生成，不同版本可能会开放新的接口，或回收一些旧接口
 * <p>
 * Auto generation by workflow engine, It cannot be manually modified
 */
@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class)
public interface WorkflowCoreService {

    /**
     * 业务节点唤醒, 该节点废弃，请换成 {@link ProcessActivityApi#trigger(cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO)} 接口
     * <p>
     * 当模型中使用了“业务节点”，且设置了“不设置审批人”模式，则当业务监听到 PROCESS_ACTIVITY_START 事件时，可通过该接口推动流程继续运行
     */
    @Deprecated
    @GetMapping("/api/process/activity/trigger")
    @InvokeMode(SYNC)
    Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);

    /**
     * 业务节点唤醒
     *
     * @param dto
     * @return
     */
    @PostMapping("/api/process/activity/trigger")
    @InvokeMode(SYNC)
    Boolean trigger(@Validated @RequestBody BpmnActivityTriggerDTO dto);

    /**
     * 业务节点设置审批人, 不支持重复设置
     * <p>
     * 当模型中使用了“业务节点”，且设置了“业务指定审批人”模式，则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时，可通过该接口设置动态设置审批人
     * <p>
     * <strong color=orange>注意：如果调用接口时，传入的审批人集合为空，流程引擎将对该审批流程实例自动中止。</strong>
     *
     * @param dto
     * @return
     */
    @PostMapping("/api/process/activity/assignee/set")
    @Operation(summary = "业务节点设置审批人，不支持重复调用设置审批人，需一次性传入所有审批人")
    @InvokeMode(SYNC)
    Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto);

    /**
     * 该功能应该利用引擎的 TimerBoundaryEvent 来实现，但为了简便，先利用引擎的任务调度来实现
     *
     * @return
     */
    @PostMapping("/api/process/activity/timeout/trigger")
    @Operation(summary = "设置指定业务节点定时继续往下执行")
    @InvokeMode(SYNC)
    Boolean setTimeoutTrigger(@Validated @RequestBody BpmnActivityTimeoutTriggerDTO dto);

    /**
     * 为指定业务节点设置定时回调
     *
     * @return
     */
    @PostMapping("/api/process/activity/timeout/callback")
    @Operation(summary = "设置指定业务节点定时回调")
    @InvokeMode(SYNC)
    Boolean setTimeoutCallback(@Validated @RequestBody BpmnActivityTimeoutCallbackDTO dto);

    /**
     * 获取指定审批业务的流程表单设置，
     * @param dto
     * @return
     */
    @PostMapping("/api/form/admin/start/form")
    @InvokeMode(SYNC)
    FormDefinitionVO getFormDefinition(@Validated @RequestBody StartFormSearchDTO dto);

    /**
     * 查询指定审批实例的表单模型和数据
     * <p>
     * dto 中的 processInstanceId 与 taskId，至少有一个属性有值，一般建议直接使用实例 ID。
     * 当传入 taskId 时，将只查询该任务绑定的表单模型和数据。
     *
     * @param dto
     * @return
     */
    @PostMapping("/api/form/admin/instance/render")
    @InvokeMode(SYNC)
    FormInstanceVO getFormInstance(@Validated @RequestBody FormDetailDTO dto);

    /**
     * 创建流程前的节点列表
     * 用于发起人自选
     *
     * @return
     */
    @Operation(summary = "创建审批流程前，返回模型节点列表以及节点能否设置审批人")
    @PostMapping("/api/process/instance/create/before")
    @InvokeMode(SYNC)
    List<NodesByModelVO> nodesBeforeCreateProcessInstance(@Validated @RequestBody BeforeProcessInstanceCreateDTO dto);

    /**
     * 创建审批流程
     *
     * <pre>
     *   MQ 触发规则:
     *     1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
     *     2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
     * </pre>
     *
     * @param dto {@link  BpmnProcessInstanceCreateDTO}
     */
    @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件")
    @PostMapping("/api/process/instance/create")
    @InvokeMode(SYNC)
    String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto);

    /**
     * 发起人主动撤回审核
     *
     * <pre>
     *   MQ 触发规则:
     *     1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
     *     2. 当前流程实例会触发 process-instance-cancelled 事件
     * </pre>
     *
     * @param dto {@link BpmnProcessInstanceCancelDTO}
     * @return
     */
    @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件")
    @DeleteMapping("/api/process/instance/cancel")
    @InvokeMode(ASYNC)
    Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto);

    /**
     * 中止流程实例
     *
     * @param dto
     * @return
     */
    @Operation(summary = "中止流程实例")
    @DeleteMapping("/api/process/instance/abort")
    @InvokeMode(ASYNC)
    Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto);

    /**
     * 批量中止流程实例
     *
     * @param dtos
     * @return
     */
    @Operation(summary = "批量中止流程实例")
    @DeleteMapping("/api/process/instance/batch/abort")
    @InvokeMode(ASYNC)
    BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List<BpmnProcessInstanceAbortDTO> dtos);

    /**
     * 获得流程实例
     *
     * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询
     * @return 流程实例, 租户Id不必传
     */
    @Operation(summary = "获得流程实例")
    @GetMapping("/api/process/instance/get")
    @InvokeMode(SYNC)
    BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto);

    /**
     * 获取指定流程实例的流程变量
     *
     * @param processInstanceId
     * @param tenantId
     * @return
     */
    @Operation(summary = "获取指定流程实例的流程变量")
    @GetMapping("/api/process/instance/cooperation-org")
    @InvokeMode(SYNC)
    Map<String, Object> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);

    /**
     * 校验指定流程实例下,是否存在指定的审批人正处理待审批
     *
     * @return true 是在当前流程实例中,存在指定的审批人
     */
    @Operation(summary = "校验指定流程实例下,是否存在指定的审批人")
    @PostMapping("/api/process/instance/check/approver")
    @InvokeMode(SYNC)
    Boolean checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto);

    /**
     * 获取指定流程的日志
     *
     * @param dto
     * @return
     */
    @Operation(summary = "获取指定流程的日志")
    @PostMapping("/api/process/instance/logs")
    @InvokeMode(SYNC)
    BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto);

    /**
     * 根据任务id查询任务状态，按钮详情
     *
     * @param taskButtonsSearchDTO 请求参数
     * @return
     */
    @Operation(summary = "根据任务id查询任务状态，按钮详情")
    @PostMapping("/api/process/instance/task/buttons/find")
    @InvokeMode(SYNC)
    BpmnTaskButtonVo findProcessSingleTaskButtons(@Validated @RequestBody BpmnTaskButtonSearchDTO taskButtonsSearchDTO);

    /**
     * 更新指定流程表单最后一次编辑的内容
     *
     * @param dto
     * @return
     */
    @Operation(summary = "更新指定流程表单最后一次编辑的内容")
    @PostMapping("/api/process/instance/form/variable/update")
    @InvokeMode(SYNC)
    Boolean updateInstanceFormVariables(@Validated @RequestBody FormVariablesUpdateDTO dto);

    /**
     * 签署业务流程实例在审批待办中查询使用的文档列表
     *
     * @return
     */
    @Operation(summary = "签署业务流程实例在审批待办中查询使用的文档列表")
    @PostMapping("/api/process/instance/select/doc/list")
    @InvokeMode(SYNC)
    List<DocPendingVO> processInstanceSelectDocs(@Validated @RequestBody ProcessDocQueryDTO dto);

    /**
     * 获取审批人阅读状态
     *
     * @return
     */
    @Operation(summary = "获取审批人阅读状态")
    @PostMapping("/api/process/instance/approver/read/status")
    @InvokeMode(SYNC)
    List<SimpleDocDTO> approverReadStatus(@Validated @RequestBody ApproverReadStatusDTO dto);

    /**
     * 修改审批人关联文档阅读状态
     */
    @Operation(summary = "修改审批人关联文档阅读状态")
    @PostMapping("/api/process/instance/approver/read/status/change")
    @InvokeMode(SYNC)
    Boolean approveReadStatusChange(@Validated @RequestBody ChangeApproverReadStatusDTO dto);

    /**
     * 获取签署业务流程最后替换的文档 fileKey 集合
     *
     * @return
     */
    @Operation(summary = "获取签署业务流程最后替换的文档 fileKey 集合")
    @GetMapping("/api/process/instance/final/docs")
    @InvokeMode(SYNC)
    List<SignFileDTO> getProcessInstanceFinalDocs(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId);

    /**
     * 同意
     *
     * <pre>
     * MQ 触发规则:
     *  1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
     *  如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
     *  2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
     *  2.2. 流程实例正常结束会触发 process-instance-completed 事件
     * </pre>
     */
    @Operation(summary = "同意，MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)，2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件，2.2. 流程实例正常结束会触发 process-instance-completed 事件")
    @PostMapping("/api/process/task/approve")
    @InvokeMode(ASYNC)
    Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto);

    /**
     * 同意时并提交表单数据
     *
     * @param dto
     * @return
     */
    @Operation(summary = "同意时并提交表单")
    @PostMapping("/api/process/task/form/approve")
    @InvokeMode(ASYNC)
    Boolean approveTaskWithForm(@Validated @RequestBody BpmnTaskAuditWithFormDTO dto);

    /**
     * 批量同意
     *
     * @param dtos
     * @return
     */
    @Operation(summary = "批量同意")
    @PostMapping("/api/process/task/batch/approve")
    @InvokeMode(ASYNC)
    BatchOperationResultVO batchApproveTask(@Validated @RequestBody List<BpmnTaskAuditDTO> dtos);

    /**
     * 获取当前节点可回退节点选项列表
     *
     * @param taskId 当前任务id
     * @return 可以回退节点列表
     */
    @Operation(summary = "获取当前节点可回退节点选项列表")
    @GetMapping("/api/process/task/back/optional/nodes")
    @InvokeMode(SYNC)
    List<BpmnOptionalNodeDTO> getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId);

    /**
     * 回退到指定节点
     *
     * @param dto
     * @return
     */
    @Operation(summary = "回退")
    @PostMapping("/api/process/task/back")
    @InvokeMode(ASYNC)
    Boolean backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto);

    /**
     * 驳回
     *
     * <pre>
     * MQ 触发规则:
     *   1. 当前审批任务会触发 process-task-deleted 事件
     *   2. 当前流程实例会触发 process-instance-rejected 事件
     * </pre>
     */
    @Operation(summary = "驳回，MQ 触发规则：1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件")
    @PostMapping("/api/process/task/reject")
    @InvokeMode(ASYNC)
    Boolean rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto);

    /**
     * 批量驳回
     *
     * @param dtos 批量请求参数
     * @return
     */
    @PostMapping("/api/process/task/batch/reject")
    @InvokeMode(ASYNC)
    BatchOperationResultVO batchRejectTask(@Validated @RequestBody List<BpmnTaskAuditDTO> dtos);

    /**
     * 转交
     *
     * @param dto
     * @return
     */
    @Operation(summary = "直接修改审批任务的审批人")
    @PostMapping("/api/process/task/transfer")
    @InvokeMode(ASYNC)
    Boolean transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto);

    /**
     * 批量转交
     *
     * @param dtos
     * @return
     */
    @Operation(summary = "批量修改审批任务的审批人")
    @PostMapping("/api/process/task/batch/transfer")
    @InvokeMode(ASYNC)
    BatchOperationResultVO batchTransferTask(@Validated @RequestBody List<BpmnTaskTransferDTO> dtos);

    /**
     * 评论
     *
     * @param dto 评论请求参数
     * @return
     */
    @Operation(summary = "审批流程评论")
    @PostMapping("/api/process/task/comment")
    @InvokeMode(ASYNC)
    Boolean commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto);

    /**
     * 加签
     *
     * @param dto 加签请求参数
     * @return
     */
    @Operation(summary = "审批流程加签")
    @PostMapping("/api/process/task/countersign")
    @InvokeMode(ASYNC)
    Boolean countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto);

    /**
     * 重置节点审批人（提级审批）
     *
     * @param dto
     * @return
     */
    @Operation(summary = "重置节点审批人（提级审批）")
    @PostMapping("/api/process/task/approvers/reset")
    @InvokeMode(ASYNC)
    Boolean resetTaskApprovers(@Validated @RequestBody BpmnTaskResetApproversDTO dto);

    /**
     * 催办
     *
     * @param dto
     * @return
     */
    @Operation(summary = "审批流程催办")
    @PostMapping("/api/process/task/remind")
    @InvokeMode(SYNC)
    Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto);

    /**
     * 暂停流程任务,并创建机器人节点,等待业务推动
     *
     * @param dto
     * @return 返回机器人节点任务 ID
     */
    @Operation(summary = "创建机器人节点, 暂停流程任务")
    @PostMapping("/api/process/task/robot/create")
    @InvokeMode(ASYNC)
    String createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto);

    /**
     * 完成机器人节点
     *
     * @param dto
     * @return
     */
    @Operation(summary = "完成机器人节点, 继续流程任务")
    @PostMapping("/api/process/task/robot/complete")
    @InvokeMode(ASYNC)
    Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto);

    /**
     * 强制使用‘异步’模式调用该方法，请在调用真实方法前调用该方法
     * <pre>
     *   workflowCoreService.async().createProcessInstance();
     * </pre>
     */
    default WorkflowCoreService sync() {
        ThreadUtil.set(SYNC);
        return this;
    }

    default WorkflowCoreService async() {
        ThreadUtil.set(ASYNC);
        return this;
    }
}
