package com.artfess.activiti.task.service.impl;

import com.artfess.activiti.cmd.SetAssigneeCmd;
import com.artfess.activiti.def.BpmDefUtil;
import com.artfess.activiti.ext.factory.BpmDelegateFactory;
import com.artfess.activiti.util.ActivitiUtil;
import com.artfess.base.util.AppUtil;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.StringUtil;
import com.artfess.bpm.api.constant.BpmConstants;
import com.artfess.bpm.api.model.delegate.BpmDelegateTask;
import com.artfess.bpm.api.service.BpmOpinionService;
import com.artfess.bpm.natapi.task.NatTaskService;
import com.artfess.bpm.persistence.manager.BpmTaskManager;
import com.artfess.bpm.persistence.model.DefaultBpmTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Service
public class TaskServiceImpl implements NatTaskService {
    @Resource
    TaskService taskService;

    @Resource
    RepositoryService repositoryService;

    @Override
    public BpmDelegateTask getByTaskId(String taskId) {
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        return BpmDelegateFactory.getBpmDelegateTask(task);
    }

    @Override
    public void save(BpmDelegateTask bpmDelegateTask) {
        TaskEntity task = (TaskEntity) bpmDelegateTask.getProxyObj();
        taskService.saveTask(task);
    }

    @Override
    public Object getVariable(String taskId, String variableName) {
        return taskService.getVariable(taskId, variableName);
    }

    @Override
    public Object getVariableLocal(String taskId, String variableName) {
        return taskService.getVariableLocal(taskId, variableName);
    }

    @Override
    public Map<String, Object> getVariables(String taskId) {
        return addNodeAuditorVar(taskService.getVariables(taskId), taskId);
    }

    @Override
    public Map<String, Object> getVariables(String taskId,
                                            Collection<String> variableNames) {
        return taskService.getVariables(taskId, variableNames);
    }

    @Override
    public Map<String, Object> getVariablesLocal(String taskId) {
        return addNodeAuditorVar(taskService.getVariablesLocal(taskId), taskId);
    }

    @Override
    public Map<String, Object> getVariablesLocal(String taskId,
                                                 Collection<String> variableNames) {
        return taskService.getVariablesLocal(taskId, variableNames);
    }

    @Override
    public void completeTask(String taskId) {
        taskService.complete(taskId);

    }

    @Override
    public void setVariable(String taskId, String variableName, Object value) {
        taskService.setVariable(taskId, variableName, value);
    }

    @Override
    public void setVariableLocal(String taskId, String variableName,
                                 Object value) {
        taskService.setVariableLocal(taskId, variableName, value);

    }

    @Override
    public void setVariables(String taskId,
                             Map<String, ? extends Object> variables) {
        taskService.setVariables(taskId, variables);

    }

    @Override
    public void setVariablesLocal(String taskId,
                                  Map<String, ? extends Object> variables) {
        taskService.setVariablesLocal(taskId, variables);
    }

    @Override
    public void completeTask(String taskId, String... aryDestination) {
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();

        String curNodeId = task.getTaskDefinitionKey();
        String actDefId = task.getProcessDefinitionId();

        Map<String, Object> activityMap = BpmDefUtil.prepare(actDefId, curNodeId, aryDestination);
        try {
            taskService.complete(taskId);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            //恢复
            BpmDefUtil.restore(activityMap);
        }
    }

    @Override
    public void setAssignee(String taskId, String userId) {
        CommandExecutor commandExecutor = ActivitiUtil.getCommandExecutor();
        SetAssigneeCmd cmd = new SetAssigneeCmd(taskId, userId);
        commandExecutor.execute(cmd);
    }

    @Override
    public void completeTaskOnly(String taskId) {
        completeTask(taskId);
    }

    private Map<String, Object> addNodeAuditorVar(Map<String, Object> variables, String taskId) {
        if (BeanUtils.isEmpty(variables)) {
            variables = new HashMap<>();
        }
        BpmTaskManager taskManager = AppUtil.getBean(BpmTaskManager.class);
        BpmOpinionService bpmOpinionService = AppUtil.getBean(BpmOpinionService.class);
        DefaultBpmTask bpmTask = taskManager.get(taskId);
        //将节点历史审批人放入变量
        Map<String, Set<String>> hisAuditors = bpmOpinionService.getHisAuditorByInstId(bpmTask.getProcInstId(), true);
        if (BeanUtils.isNotEmpty(hisAuditors)) {
            for (String nodeId : hisAuditors.keySet()) {
                variables.put(BpmConstants.NODE_AUDITOR_VAR_PREFIX + nodeId, StringUtil.join(hisAuditors.get(nodeId)));
            }
        }
        return variables;
    }
}