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

import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
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.BpmnProcessInstanceCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO;
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.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO;
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.ProcessNodeDetailVO;
import cn.azxo.framework.common.model.CommonResponse;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.cloud.openfeign.FeignClient;
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;

/**
 * 流程实例 API
 *
 * @author wangli
 * @since 2023/9/21 16:26
 */
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}")
public interface ProcessInstanceApi {
    /**
     * 查询所有的审批流
     *
     * @return
     */
    @PostMapping("/api/process/instance/page/all")
    CommonResponse<BpmPageResult<BpmnProcessInstanceAdminPageItemVO>> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto);

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

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

    /**
     * 创建审批流程并带上表单
     *
     * @param dto
     * @return
     */
    @PostMapping("/api/process/instance/form/create")
    CommonResponse<String> createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto);

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

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

    /**
     * 抄送流程实例
     *
     * @param dto
     * @return
     */
    @PostMapping("/api/process/instance/carbon-copy")
    CommonResponse<Boolean> carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto);

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

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

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

    /**
     * 推断指定流程实例的所有节点执行顺序
     *
     * @return
     */
    @GetMapping("/api/process/instance/node/forecasting")
    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
     */
    @GetMapping("/api/process/instance/node/filter/forecasting")
    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);

    /**
     * 获取指定流程实例的协作单位
     *
     * @param processInstanceId
     * @param tenantId
     * @return
     */
    @GetMapping("/api/process/instance/cooperation-org")
    CommonResponse<CooperationOrgDTO> getCooperationOrg(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
                                                        @Nullable @RequestParam(required = false) String tenantId);

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