package cn.axzo.workflow.server.controller.web.bpmn;

import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi;
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.request.bpmn.process.HistoricProcessInstanceSearchDTO;
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.HistoricProcessInstanceVO;
import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO;
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.history.HistoricProcessInstance;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

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

import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
import static cn.azxo.framework.common.model.CommonResponse.success;

/**
 * 流程实例相关控制器
 */
@Slf4j
@RequestMapping({"/web/v1/api/process/instance", "/api/process/instance"})
@RestController
@ErrorReporter
@Validated
public class BpmnProcessInstanceController implements ProcessInstanceApi {

    @Resource
    private BpmnProcessInstanceService bpmnProcessInstanceService;

    /**
     * 超管查询所有流程实例
     *
     * @param dto
     * @return
     */
    @Operation(summary = "超管查询所有流程实例")
    @PostMapping("/page/all")
    @Override
    public CommonResponse<BpmPageResult<BpmnProcessInstanceAdminPageItemVO>> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto) {
        log.info("超管查询审批列表 getAllProcessInstancePage===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.getAdminProcessInstancePage(dto));
    }

    /**
     * 我发起的审批列表
     */
    @Operation(summary = "我发起的审批列表")
    @PostMapping("/page/my")
    @Override
    public CommonResponse<BpmPageResult<BpmnProcessInstancePageItemVO>> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto) {
        log.info("我发起的审批列表 getOwnTaskPage===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.getMyProcessInstancePage(dto));
    }

    /**
     * 创建审批实例
     */
    @Operation(summary = "创建流程实例")
    @PostMapping("/create")
    @Override
    @RepeatSubmit
    public CommonResponse<String> createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto) {
        log.info("发起审核createProcessInstance===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.createProcessInstance(dto));
    }

    /**
     * 创建审批流程并带上表单
     *
     * @param dto
     * @return
     */
    @Operation(summary = "创建审批流程并带上表单")
    @PostMapping("/form/create")
    @Override
    @RepeatSubmit
    public CommonResponse<String> createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto) {
        log.info("发起审核createProcessInstanceWith===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.createProcessInstanceWithForm(dto));
    }

    /**
     * 撤回流程实例
     *
     * @param dto
     * @return
     */
    @Operation(summary = "撤回流程实例")
    @DeleteMapping("/cancel")
    @Override
    @RepeatSubmit
    public CommonResponse<Boolean> cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto) {
        log.info("撤回审核cancelProcessInstant===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.cancelProcessInstance(dto));
    }

    /**
     * 中止流程实例
     *
     * @param dto
     * @return
     */
    @Operation(summary = "中止流程实例")
    @Override
    @DeleteMapping("/abort")
    @RepeatSubmit
    public CommonResponse<Boolean> abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto) {
        log.info("中止流程实例abortProcessInstant===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.abortProcessInstance(dto));
    }

    /**
     * 抄送流程
     *
     * @param dto
     * @return
     */
    @Operation(summary = "抄送流程")
    @RepeatSubmit
    @PostMapping("/carbon-copy")
    @Override
    public CommonResponse<Boolean> carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto) {
        log.info("抄送流程实例carbonCopyProcessInstance===>>>参数：{}", JSONUtil.toJsonStr(dto));
        return success(bpmnProcessInstanceService.carbonCopyProcessInstance(dto));
    }

    /**
     * 获得流程实例
     *
     * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询
     * @return 流程实例, 租户Id不必传
     */
    @Operation(summary = "获得流程实例")
    @GetMapping("/get")
    @Override
    public CommonResponse<BpmnProcessInstanceVO> getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto) {
        log.info("获得历史的流程实例 getProcessInstanceVO===>>>参数：{}", JSONUtil.toJsonStr(dto));
        BpmnProcessInstanceVO result = bpmnProcessInstanceService.getProcessInstanceVO(dto);
        return success(result);
    }

    /**
     * 更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例
     *
     * @param processDefinitionId 流程定义的编号
     * @param status              1, "active"; 2, "suspended"
     */
    @Operation(summary = "更新指定流程定义的版本的状态")
    @PutMapping("/status/update")
    @RepeatSubmit
    @Override
    public CommonResponse<Boolean> updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId,
                                                       @NotNull(message = "状态不能为空") @RequestParam Integer status) {
        log.info("获得流程实例 updateProcessStatus===>>>参数：{},{}", processDefinitionId, status);
        Boolean result = bpmnProcessInstanceService.updateProcessStatus(processDefinitionId, status);
        return success(result);
    }

    /**
     * 获取审批流程实例的运行图
     *
     * @param processInstanceId 流程实例 ID
     * @param tenantId          租户 ID
     * @return
     */
    @Operation(summary = "获取审批流程实例的运行图")
    @GetMapping("/graphical")
    @Override
    public CommonResponse<ObjectNode> processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
                                                               @Nullable @RequestParam(required = false) String tenantId) {
        return success(bpmnProcessInstanceService.getProcessInstanceGraphical(processInstanceId, tenantId));
    }

    /**
     * 获取指定实例的全节点执行顺序推算
     *
     * @param processInstanceId
     * @param tenantId
     * @return
     */
    @Operation(summary = "获取指定实例的全节点执行顺序推算")
    @GetMapping("/node/forecasting")
    @Override
    public CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
                                                                                 @Nullable String tenantId) {
        return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId));
    }

    /**
     * 推断指定流程实例的过滤掉部分节点执行顺序
     *
     * @param processInstanceId
     * @param tenantId
     * @param allNode            如果为真时,相当于调用 {@link ProcessInstanceApi#processInstanceNodeForecast(String, String)} 方法,切会直接丢弃 nodeDefinitionKeys 参数
     *                           如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点
     * @param nodeDefinitionKeys
     * @return
     */
    @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序")
    @GetMapping("/node/filter/forecasting")
    @Override
    public 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) {
        if (allNode) {
            return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId));
        } else {
            return success(bpmnProcessInstanceService.getProcessInstanceNodeFilterForecast(processInstanceId, tenantId, nodeDefinitionKeys));
        }
    }

    /**
     * 获取指定流程实例的协作单位
     *
     * @param processInstanceId
     * @param tenantId
     * @return
     */
    @Operation(summary = "获取指定流程实例的协作单位")
    @GetMapping("/cooperation-org")
    @Override
    @RepeatSubmit
    public CommonResponse<CooperationOrgDTO> getCooperationOrg(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
                                                               @Nullable String tenantId) {
        HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId,
                tenantId, true);
        return success((CooperationOrgDTO) processInstance.getProcessVariables().get(BIZ_ORG_RELATION));
    }

    /**
     * 枢智业务(审批台账专用)
     *
     * @return
     */
    @Operation(summary = "查询模型的租户集合")
    @GetMapping("/historic/page")
    public CommonResponse<BpmPageResult<HistoricProcessInstanceVO>> historicInstancePage(@RequestBody HistoricProcessInstanceSearchDTO dto) {
        return success(bpmnProcessInstanceService.historicProcessInstancePage(dto));
    }

    /**
     * 查询实例的租户集合
     *
     * @return
     */
    @Operation(summary = "查询实例的租户集合")
    @Override
    @GetMapping("/tenant/ids")
    public CommonResponse<List<String>> getTenantIds() {
        return success(bpmnProcessInstanceService.getTenantIds());
    }
}
