package cn.axzo.workflow.client.feign.bpmn;

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.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.BpmnProcessInstanceBatchQueryDTO;
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 cn.azxo.framework.common.model.CommonResponse;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Nullable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;

import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;

/**
 * 流程实例 API
 *
 * @author wangli
 * @since 2023/9/21 16:26
 */
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
@WorkflowEngineFeignClient
public interface ProcessInstanceApi {

    /**
     * 创建流程前的节点列表
     * 用于发起人自选
     *
     * @return
     */
    @Operation(summary = "创建审批流程前，返回模型节点列表以及节点能否设置审批人")
    @PostMapping("/api/process/instance/create/before")
    @InvokeMode(SYNC)
    CommonResponse<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)
    CommonResponse<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)
    CommonResponse<Boolean> cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto);

    @DeleteMapping("/api/process/instance/super/cancel")
    @Manageable
    CommonResponse<Boolean> superCancelProcessInstance(@Validated @RequestBody SuperBpmnProcessInstanceCancelDTO dto);

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

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

    /**
     * 抄送流程实例（未实现）
     *
     * @param dto
     * @return
     */
    @Operation(summary = "抄送流程实例")
    @PostMapping("/api/process/instance/carbon-copy")
    @Deprecated
    CommonResponse<Boolean> carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto);

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

    /**
     * 批量获得流程实例
     *
     * @param dto
     * @return
     */
    @Operation(summary = "批量获得流程实例")
    @PostMapping("/api/process/instance/batch/get")
    @InvokeMode(SYNC)
    CommonResponse<List<BpmnProcessInstanceVO>> getBatchProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceBatchQueryDTO dto);

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

    /**
     * 查询所有的审批流
     *
     * @return
     */
    @Operation(summary = "查询所有的审批流")
    @PostMapping("/api/process/instance/page/all")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<BpmPageResult<BpmnProcessInstanceAdminPageItemVO>> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto);

    /**
     * 我发起的审批列表
     */
    @Operation(summary = "我发起的审批列表")
    @PostMapping("/api/process/instance/page/my")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<BpmPageResult<BpmnProcessInstancePageItemVO>> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto);

    /**
     * 更新流程定义的状态
     *
     * @param processDefinitionId 流程定义的编号
     * @param status              1, "active"; 2, "suspended"
     */
    @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例")
    @PutMapping("/api/process/instance/status/update")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<Boolean> updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId,
                                                @NotNull(message = "状态不能为空") @RequestParam Integer status);

    /**
     * 获取审批流程实例的运行图
     *
     * @param processInstanceId
     * @param tenantId
     * @return
     */
    @Operation(summary = "获取审批流程实例的运行图")
    @GetMapping("/api/process/instance/graphical")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<ObjectNode> processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
                                                        @Nullable @RequestParam(required = false) String tenantId);

    /**
     * 推断指定流程实例的所有节点执行顺序
     *
     * @return
     */
    @Operation(summary = "推断指定流程实例的所有节点执行顺序")
    @GetMapping("/api/process/instance/node/forecasting")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId,
                                                                          @Nullable @RequestParam(required = false) String tenantId);

    /**
     * 推断指定流程实例的过滤掉部分节点执行顺序
     *
     * @param allNode 如果为真时,相当于调用 {@link ProcessInstanceApi#processInstanceNodeForecast(String, String)} 方法,切会直接丢弃 nodeDefinitionKeys 参数
     *                如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点
     * @return
     */
    @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序")
    @GetMapping("/api/process/instance/node/filter/forecasting")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<List<ProcessNodeDetailVO>> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId,
                                                                                @Nullable @RequestParam(required = false) String tenantId,
                                                                                @RequestParam(required = false, defaultValue = "false") Boolean allNode,
                                                                                @Nullable @RequestParam(required = false) List<String> nodeDefinitionKeys);

    /**
     * 查询实例的租户集合
     *
     * @return
     */
    @Operation(summary = "查询实例的租户集合")
    @GetMapping("/api/process/instance/tenant/ids")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<List<String>> getTenantIds();

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

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

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

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

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

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

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

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

    /**
     * 查询 ExtAxProcessLog 表中审批人的冗余信息
     *
     * @param dto
     * @return
     */
    @Operation(summary = "查询 ExtAxProcessLog 表中审批人的冗余信息")
    @GetMapping("/api/process/instance/log/approve/ext")
    @Manageable
    @InvokeMode(SYNC)
    CommonResponse<List<ExtProcessLogVO>> getProcessLogByInstanceIdAndPersonId(@Validated @RequestBody LogApproveSearchDTO dto);
}
