package cn.axzo.workflow.core.service.impl;

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.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.CustomAbortProcessInstanceCmd;
import cn.axzo.workflow.core.engine.cmd.CustomActivityTriggerAsyncCmd;
import cn.axzo.workflow.core.engine.cmd.CustomActivityTriggerCmd;
import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskAsyncCmd;
import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd;
import cn.axzo.workflow.core.engine.cmd.CustomBusinessNodeTimeoutCallbackCmd;
import cn.axzo.workflow.core.engine.cmd.CustomBusinessNodeTimeoutTriggerCmd;
import cn.axzo.workflow.core.service.BpmnProcessActivityService;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.Execution;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Objects;

import static cn.axzo.workflow.common.code.BpmnTaskRespCode.ACTIVITY_TRIGGER_NOT_EXISTS;


@Service
@Slf4j
public class BpmnProcessActivityServiceImpl implements BpmnProcessActivityService {

    @Resource
    @Lazy
    private RuntimeService runtimeService;
    @Resource
    private ExtAxHiTaskInstService extAxHiTaskInstService;
    @Resource
    @Lazy
    private SpringProcessEngineConfiguration processEngineConfiguration;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void trigger(BpmnActivityTriggerDTO dto) {
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
        if (Boolean.TRUE.equals(dto.getAsync())) {
            commandExecutor.execute(new CustomActivityTriggerAsyncCmd(dto));
        } else {
            commandExecutor.execute(new CustomActivityTriggerCmd(dto));
        }
    }

    @Override
    public void setAssignee(BpmnActivitySetAssigneeDTO dto) {
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
        if (CollectionUtils.isEmpty(dto.getAssigners())) {
            Execution execution = runtimeService.createExecutionQuery().executionId(dto.getTriggerId()).singleResult();
            if (Objects.isNull(execution)) {
                throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, dto.getTriggerId());
            }
            BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO();
            abortDTO.setProcessInstanceId(execution.getProcessInstanceId());
            abortDTO.setReason("业务未指定审批人");
            commandExecutor.execute(new CustomAbortProcessInstanceCmd(abortDTO, extAxHiTaskInstService));
            return;
        }

        if (Boolean.TRUE.equals(dto.getAsync())) {
            commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskAsyncCmd(dto));
        } else {
            commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskCmd(dto.getTriggerId(), dto.getAssigners()));
        }
    }

    @Override
    public Boolean setTimeoutTrigger(BpmnActivityTimeoutTriggerDTO dto) {
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
        commandExecutor.execute(new CustomBusinessNodeTimeoutTriggerCmd(dto.getTriggerId(), dto.getEndTime(),
                dto.getVariables()));
        return true;
    }

    /**
     * 设置指定业务节点定时回调
     *
     * @param dto
     * @return
     */
    @Override
    public Boolean setTimeOutCallback(BpmnActivityTimeoutCallbackDTO dto) {
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
        commandExecutor.execute(new CustomBusinessNodeTimeoutCallbackCmd(dto.getTriggerId(), dto.getEndTime(), dto.getVariables()));
        return true;
    }
}
