package com.codvision.workflow.listener.task;


import com.codvision.auth.entity.SysRole;
import com.codvision.auth.entity.vo.SysUserVO;
import com.codvision.auth.service.ISysRoleService;
import com.codvision.auth.service.ISysUserService;
import com.codvision.commoncore.exception.BusinessException;
import com.codvision.commoncore.utils.Preconditions;
import com.codvision.workflow.entity.WorkFlowRecord;
import com.codvision.workflow.entity.dto.WorkFlowDynamicAllocationDTO;
import com.codvision.workflow.service.WorkFlowRecordService;
import com.codvision.workflow.service.WorkFlowService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.codvision.workflow.constant.WorkFlowConstant.TASK_DYNAMIC_HANDLER;
import static com.codvision.workflow.constant.WorkFlowConstant.TASK_ROLR;
import static com.codvision.workflow.constant.enums.WorkFlowOperationTypeEnum.RETURN;


/**
 * 动态分配处理人或处理组织（任务监听器 事件类型 -> create）
 * @author hxl
 */
@RequiredArgsConstructor
@Component(value = "workFlowDynamicAllocationListener")
public class WorkFlowDynamicAllocationListener {

    private final TaskService taskService;
    private final WorkFlowService workFlowService;
    private final WorkFlowRecordService workFlowRecordService;
    private final ISysUserService sysUserService;
    private final ISysRoleService sysRoleService;
    private final RuntimeService runtimeService;

    /**
     * 分配组织
     * @param delegateTask 当前任务
     * @param oid 组织ID
     * @param roleId 角色ID，可以为空
     */
    public void setOrg(DelegateTask delegateTask, Integer oid, Long roleId) {
        if (oid == null) {
            return;
        }

        if (roleId != null) {
            SysRole sysRole = sysRoleService.getById(roleId);
            if (sysRole == null) {
                return;
            }

            taskService.setVariableLocal(delegateTask.getId(), TASK_ROLR, roleId);
        }

        workFlowService.clearCandidates(delegateTask.getId());
        taskService.addCandidateGroup(delegateTask.getId(), oid.toString());
    }

    /**
     * 分配用户
     * @param delegateTask 当前任务
     * @param oid 组织OID
     * @param roleId 角色ID, 可以为空
     */
    public void setAssignees(DelegateTask delegateTask, Integer oid, Long roleId) {
        if (oid == null) {
            return;
        }

        workFlowService.clearCandidates(delegateTask.getId());
        delegateTask.addCandidateUsers(getNextUserIds(oid, roleId));
    }

    /**
     * 分配用户
     * @param delegateTask 当前任务
     * @param variableName 表单字段
     */
    public void setAssignee(DelegateTask delegateTask, String variableName) {
        if (StringUtils.isBlank(variableName)) {
            return;
        }

        String variable = (String) taskService.getVariable(delegateTask.getId(), variableName);
        if (StringUtils.isBlank(variable)) {
            return;
        }

        workFlowService.clearCandidates(delegateTask.getId());
        delegateTask.addCandidateUsers(Collections.singletonList(variable));
    }


    /**
     * 分配用户或组织（配合动态表单组件使用）
     * @param delegateTask 当前任务
     * @param roleId 角色ID，可以为空，使用场景：分配组织时可指定具体的角色
     */
    public void setAssigneesOrOrg(DelegateTask delegateTask, Long roleId) {
        // 兼容退回操作
        WorkFlowRecord workFlowRecord = workFlowRecordService.getLatestByInstanceId(delegateTask.getProcessInstanceId());
        if (workFlowRecord != null && workFlowRecord.getAction() != null && RETURN.getType() == workFlowRecord.getAction()) {
            List<ActivityInstance> activityInstances = runtimeService.createActivityInstanceQuery()
                    .processInstanceId(delegateTask.getProcessInstanceId()).activityId(delegateTask.getTaskDefinitionKey()).finished().orderByActivityInstanceEndTime().desc().list();
            if (CollectionUtils.isEmpty(activityInstances)) {
                return;
            }

            ActivityInstance activityInstance = activityInstances.get(0);
            delegateTask.addCandidateUsers(Collections.singletonList(activityInstance.getAssignee()));
            return;
        }

        workFlowService.clearCandidates(delegateTask.getId());
        WorkFlowDynamicAllocationDTO allocation = (WorkFlowDynamicAllocationDTO) taskService.getVariable(delegateTask.getId(), TASK_DYNAMIC_HANDLER);
        if (allocation == null) {
            throw new BusinessException("获取动态分配处理人或处理组织信息失败");
        }

        if (allocation.getAllocationType() == null) {
            return;
        }

        if (allocation.getAllocationType() == 0) {
            if (CollectionUtils.isEmpty(allocation.getUserIdList())) {
                return;
            }
            delegateTask.addCandidateUsers(allocation.getUserIdList().stream().map(String::valueOf).collect(Collectors.toList()));
        } else {
            Integer oid = allocation.getOid();
            if (oid == null) {
                return;
            }

            if (roleId != null) {
                delegateTask.addCandidateUsers(getNextUserIds(oid, roleId));
            } else {
                taskService.addCandidateGroup(delegateTask.getId(), oid.toString());
            }
        }
    }



    /**
     * 由下而上逐级设置处理人
     * @param delegateTask 当前任务
     * @param isFirstUserTask 是否为流程中第一个用户节点
     * @param roleId 角色ID，可以为空
     */
    public void setParentOrgAssignee(DelegateTask delegateTask, Boolean isFirstUserTask, Long roleId) {
        if (isFirstUserTask == null) {
            return;
        }

        String userId = null;
        if (isFirstUserTask) {
            // 获取发起人ID
            userId = (String) delegateTask.getVariable(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR);
        } else {
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(delegateTask.getProcessInstanceId())
                    .orderByTaskCreateTime().desc().list();
            if (CollectionUtils.isNotEmpty(taskList)) {
                // 获取上一个任务节点的办理人ID
                userId = taskList.get(0).getAssignee();
            }
        }

        if (StringUtils.isNotBlank(userId)) {
            SysUserVO sysUserVO = sysUserService.getDetail(Integer.valueOf(userId));
            Preconditions.checkArgument(sysUserVO != null, "获取发起人或上一步办理人用户信息失败");
            delegateTask.addCandidateUsers(getNextUserIds(sysUserVO.getActivePoid(), roleId));
        }
    }


    private List<String> getNextUserIds(Integer oid, Long roleId) {
        Map<String, Object> paraMap = new HashMap<>(16);
        paraMap.put("oid", oid);
        if (roleId != null) {
            paraMap.put("roleId", roleId);
        }

        List<SysUserVO> sysUserVOList = sysUserService.listUsers(paraMap);
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(sysUserVOList), "获取下一步办理人信息失败");
        return sysUserVOList.stream().map(SysUserVO::getId).map(String::valueOf).collect(Collectors.toList());
    }
}
