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.BpmnProcessInstanceCancelDTO;
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.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.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
import cn.azxo.framework.common.model.CommonResponse;
import com.alibaba.fastjson.JSON;
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.util.StringUtils;
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.axzo.workflow.core.common.enums.BpmnErrorCode.PROCESS_OPERATION_PARAM_VALID_ERROR;
import static cn.azxo.framework.common.model.CommonResponse.success;

@Slf4j
@RequestMapping({"/web/v1/api/process/instance", "/api/process/instance"})
@RestController
@Validated
public class BpmnProcessInstanceController implements ProcessInstanceApi {

    @Resource
    private BpmnProcessInstanceService bpmnProcessInstanceService;

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

    /**
     * 发起审核
     */
    @PostMapping("/create")
    @Override
    public CommonResponse<String> createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto) {
        log.info("发起审核createProcessInstance===>>>参数：{}", JSON.toJSONString(dto));
        String result = bpmnProcessInstanceService.createProcessInstance(dto);
        return success(result);
    }

    @PostMapping("/form/create")
    @Override
    public CommonResponse<String> createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto) {
        log.info("发起审核createProcessInstanceWith===>>>参数：{}", JSON.toJSONString(dto));
        String result = bpmnProcessInstanceService.createProcessInstanceWithForm(dto);
        return success(result);
    }

    /**
     * 取消流程实例
     *
     * @param dto
     * @return
     */
    @DeleteMapping("/cancel")
    @Override
    public CommonResponse<Boolean> cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto) {
        log.info("取消审核cancelProcessInstant===>>>参数：{}", JSON.toJSONString(dto));
        if (!StringUtils.hasLength(dto.getId()) && !StringUtils.hasLength(dto.getBusinessKey())) {
            throw new WorkflowEngineException(PROCESS_OPERATION_PARAM_VALID_ERROR);
        }
        return success(bpmnProcessInstanceService.cancelProcessInstance(dto));
    }

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

    /**
     * 获得流程实例
     *
     * @param processDefinitionId 流程定义的编号
     * @param status              1, "active"; 2, "suspended"
     */
    @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例")
    @PutMapping("/status/update")
    @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);
    }

    @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
     */
    @GetMapping("/node/forecasting")
    @Override
    public CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
                                                                                 @Nullable String tenantId) {
        return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId));
    }

    @GetMapping("/cooperation-org")
    @Override
    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
     */
    @GetMapping("/historic/page")
    public CommonResponse<BpmPageResult<HistoricProcessInstanceVO>> historicInstancePage(@RequestBody HistoricProcessInstanceSearchDTO dto) {
        return success(bpmnProcessInstanceService.historicProcessInstancePage(dto));
    }

}
