package com.yunzhupaas.flowable.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.ImmutableList;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.flowable.entity.*;
import com.yunzhupaas.flowable.enums.DivideRuleEnum;
import com.yunzhupaas.flowable.enums.NodeEnum;
import com.yunzhupaas.flowable.enums.OperatorStateEnum;
import com.yunzhupaas.flowable.enums.TaskStatusEnum;
import com.yunzhupaas.flowable.model.flowable.FlowAbleUrl;
import com.yunzhupaas.flowable.model.flowable.FlowableHistoricModel;
import com.yunzhupaas.flowable.model.task.FlowMethod;
import com.yunzhupaas.flowable.model.task.FlowModel;
import com.yunzhupaas.flowable.model.templatenode.TaskNodeModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.AuxiliaryInfo;
import com.yunzhupaas.flowable.model.templatenode.nodejson.AuxiliaryInfoConfig;
import com.yunzhupaas.flowable.model.templatenode.nodejson.NodeModel;
import com.yunzhupaas.flowable.model.util.FlowNature;
import com.yunzhupaas.flowable.service.OperatorService;
import com.yunzhupaas.flowable.service.RevokeService;
import com.yunzhupaas.flowable.service.TaskService;
import com.yunzhupaas.flowable.service.TriggerRecordService;
import com.yunzhupaas.model.document.FlowFileModel;
import com.yunzhupaas.permission.entity.UserEntity;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/4/29 10:29
 */
@Component
public class NodeUtil {
    @Autowired
    private FlowAbleUrl flowAbleUrl;
    @Autowired
    private ServiceUtil serviceUtil;
    @Autowired
    private TaskUtil taskUtil;
    @Autowired
    private OperatorService operatorService;
    @Autowired
    private OperatorUtil operatorUtil;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RevokeService revokeService;
    @Autowired
    private TriggerRecordService triggerRecordService;

    public List<TaskNodeModel> getNodeList(FlowModel flowModel) throws WorkFlowException {
        List<TaskNodeModel> nodeList = new ArrayList<>();
        TaskEntity taskEntity = flowModel.getTaskEntity();
        // 终止后 任务详情的流程图，需全部置灰
        if (ObjectUtil.equals(TaskStatusEnum.CANCEL.getCode(), taskEntity.getStatus())) {
            return nodeList;
        }
        List<TemplateNodeEntity> nodeEntities = flowModel.getNodeEntityList();
        // 当前节点
        String currentNodeCode = StringUtil.isNotEmpty(taskEntity.getCurrentNodeCode())
                ? taskEntity.getCurrentNodeCode()
                : "";
        List<String> currentNodes = new ArrayList<>(Arrays.asList(currentNodeCode.split(",")));
        // 未经过的节点
        List<String> tobePass = flowAbleUrl.getTobePass(taskEntity.getInstanceId());
        if (currentNodeCode.equals(FlowNature.END_CODE)) {
            currentNodes = nodeEntities.stream()
                    .filter(t -> NodeEnum.end.getType().equals(t.getNodeType())).map(TemplateNodeEntity::getNodeCode)
                    .collect(Collectors.toList());
        }
        // 经过的节点
        FlowMethod flowMethod = new FlowMethod();
        flowMethod.setTobePass(tobePass);
        flowMethod.setCurrentNodes(currentNodes);
        flowMethod.setTaskId(taskEntity.getId());
        flowMethod.setTaskEntity(taskEntity);
        flowMethod.setNodeEntityList(nodeEntities);
        List<String> passed = this.getPassed(flowMethod);
        TemplateNodeEntity start = nodeEntities.stream().filter(e -> e.getNodeType().equals(NodeEnum.start.getType()))
                .findFirst().orElse(null);
        if (start != null) {
            passed.add(start.getNodeCode());
        }

        List<TriggerRecordEntity> triggerRecordList = triggerRecordService.getListByTaskId(taskEntity.getId());

        List<String> typeList = ImmutableList.of(NodeEnum.global.getType(), NodeEnum.connect.getType(), "confluence",
                "gateway");
        List<String> divideList = Arrays.stream(DivideRuleEnum.values()).map(DivideRuleEnum::getType)
                .collect(Collectors.toList());
        divideList.addAll(typeList);

        flowMethod.setFlowModel(flowModel);
        flowMethod.setErrorRule(false);
        flowMethod.setExtraRule(true);

        // 节点 (-1没有经过,0.经过 1.当前 2.未经过)
        for (TemplateNodeEntity node : nodeEntities) {
            String nodeCode = node.getNodeCode();
            // 跳过全局节点、连接线
            if (divideList.contains(node.getNodeType())) {
                continue;
            }
            TaskNodeModel model = JsonUtil.getJsonToBean(node, TaskNodeModel.class);
            // 节点名称
            NodeModel nodeModel = JsonUtil.getJsonToBean(node.getNodeJson(), NodeModel.class);
            model.setNodeName(nodeModel.getNodeName());
            if (CollectionUtil.isNotEmpty(currentNodes)) {
                if (currentNodes.contains(nodeCode)) {
                    model.setType("1");
                    if (NodeEnum.end.getType().equals(node.getNodeType())) {
                        model.setType("0");
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(passed)) {
                if (passed.contains(nodeCode)) {
                    model.setType("0");
                }
            }
            TriggerRecordEntity triggerRecord = triggerRecordList.stream()
                    .filter(e -> ObjectUtil.equals(e.getNodeCode(), nodeModel.getNodeId())).findFirst().orElse(null);
            if (null != triggerRecord) {
                String type = "1";
                if (ObjectUtil.equals(triggerRecord.getStatus(), 0)) {
                    type = "0";
                } else if (ObjectUtil.equals(triggerRecord.getStatus(), 1)) {
                    type = "3";
                }
                model.setType(type);
            }

            List<String> userNameList = new ArrayList<>();

            if (StringUtil.equals(node.getNodeType(), NodeEnum.start.getType())) {
                List<String> userIds = new ArrayList<>();
                userIds.add(taskEntity.getCreatorUserId());
                List<UserEntity> users = serviceUtil.getUserName(userIds);
                UserEntity user = users.get(0);
                userNameList.add(user.getRealName() + "/" + user.getAccount());
                if (!TaskStatusEnum.TO_BE_SUBMIT.getCode().equals(taskEntity.getStatus())) {
                    model.setType("0");
                }
            } else if (StringUtil.equals(node.getNodeType(), NodeEnum.subFlow.getType())) {
                QueryWrapper<TaskEntity> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(TaskEntity::getParentId, taskEntity.getId()).eq(TaskEntity::getSubCode,
                        node.getNodeCode());
                List<TaskEntity> list = taskService.list(queryWrapper);
                List<String> userIds;
                if (CollectionUtil.isNotEmpty(list)) {
                    userIds = list.stream().map(TaskEntity::getCreatorUserId).collect(Collectors.toList());
                } else {
                    flowMethod.setNodeEntity(node);
                    userIds = taskUtil.userListAll(flowMethod);
                }
                List<UserEntity> users = serviceUtil.getUserName(userIds);
                if (CollectionUtil.isNotEmpty(users)) {
                    for (UserEntity user : users) {
                        userNameList.add(user.getRealName() + "/" + user.getAccount());
                    }
                }
            } else if (StringUtil.equals(node.getNodeType(), NodeEnum.approver.getType())
                    || StringUtil.equals(node.getNodeType(), NodeEnum.processing.getType())) {
                List<String> userIds;
                List<OperatorEntity> operatorList = operatorUtil.getByNodeCode(taskEntity.getId(), node.getNodeCode());

                Integer counterSign = nodeModel.getCounterSign();

                // 获取生成经办的人
                List<Integer> statusList = ImmutableList.of(OperatorStateEnum.Revoke.getCode(),
                        OperatorStateEnum.AddSign.getCode(), OperatorStateEnum.Assist.getCode());
                List<OperatorEntity> list = operatorList.stream()
                        .filter(e -> !statusList.contains(e.getStatus()) && ObjectUtil.equals(e.getParentId(), "0"))
                        .collect(Collectors.toList());
                userIds = list.stream().map(OperatorEntity::getHandleId).collect(Collectors.toList());
                // 依次审批
                if (counterSign.equals(FlowNature.ImproperApprover)) {
                    OperatorEntity last = list.stream().filter(e -> e.getCompletion().equals(0)).findFirst()
                            .orElse(null);
                    if (null != last && StringUtil.isNotBlank(last.getHandleAll())) {
                        String[] split = last.getHandleAll().split(",");
                        userIds = Arrays.stream(split).collect(Collectors.toList());
                    }
                }

                // 经办处理人的id为0，为系统自动通过
                if (userIds.contains(FlowNature.SYSTEM_CODE)) {
                    // model.setUserName(FlowNature.SYSTEM_NAME);
                    nodeList.add(model);
                    continue;
                }
                if (CollectionUtil.isEmpty(userIds)) {
                    flowMethod.setNodeEntity(node);
                    userIds = taskUtil.userListAll(flowMethod);
                }
                if (CollectionUtil.isEmpty(userIds)) {
                    nodeList.add(model);
                    continue;
                }
                userIds = userIds.stream().distinct().sorted().collect(Collectors.toList());
                List<UserEntity> users = serviceUtil.getUserName(userIds);

                if (CollectionUtil.isNotEmpty(users)) {
                    for (String userId : userIds) {
                        UserEntity user = users.stream().filter(e -> e.getId().equals(userId)).findFirst().orElse(null);
                        if (null != user) {
                            userNameList.add(user.getRealName() + "/" + user.getAccount());
                        }
                    }
                }
            }
            model.setUserName(String.join(",", userNameList));
            nodeList.add(model);
        }
        return nodeList;
    }

    /**
     * 经过的节点
     */
    public List<String> getPassed(FlowMethod flowMethod) {
        List<String> tobePass = flowMethod.getTobePass();
        List<String> currentNodes = flowMethod.getCurrentNodes();
        TaskEntity taskEntity = flowMethod.getTaskEntity();
        String taskId = flowMethod.getTaskId();
        List<TemplateNodeEntity> nodeEntityList = flowMethod.getNodeEntityList();
        List<String> resList = new ArrayList<>();

        QueryWrapper<OperatorEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(OperatorEntity::getTaskId, taskId).ne(OperatorEntity::getStatus,
                OperatorStateEnum.Futility.getCode());
        List<OperatorEntity> operatorList = operatorService.list(wrapper);
        if (CollectionUtil.isNotEmpty(operatorList)) {
            List<String> nodeCodes = operatorList.stream().map(OperatorEntity::getNodeCode)
                    .filter(e -> !currentNodes.contains(e)).collect(Collectors.toList());
            resList.addAll(nodeCodes);
        }

        RevokeEntity revokeEntity = revokeService.getRevokeTask(taskEntity.getId());
        if (null != revokeEntity) {
            taskId = revokeEntity.getTaskId();
        }
        if (!ObjectUtil.equals(TaskStatusEnum.BACKED.getCode(), taskEntity.getStatus())) {
            QueryWrapper<TaskEntity> taskWrapper = new QueryWrapper<>();
            taskWrapper.lambda().eq(TaskEntity::getParentId, taskId);
            List<TaskEntity> subFlowList = taskService.list(taskWrapper);
            List<String> historic = new ArrayList<>();
            try {
                historic = flowAbleUrl.getHistoric(taskEntity.getInstanceId()).stream()
                        .map(FlowableHistoricModel::getCode).collect(Collectors.toList());
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (CollectionUtil.isNotEmpty(subFlowList)) {
                List<String> subCodes = subFlowList.stream().map(TaskEntity::getSubCode)
                        .filter(e -> !currentNodes.contains(e) && !tobePass.contains(e))
                        .collect(Collectors.toList());
                if (null != revokeEntity) {
                    subCodes = subCodes.stream().filter(historic::contains).collect(Collectors.toList());
                }
                resList.addAll(subCodes);
            }
            // 撤销会跳过办理节点
            if (null != revokeEntity) {
                List<String> finalHistoric = historic;
                List<String> processingList = nodeEntityList.stream()
                        .filter(e -> ObjectUtil.equals(e.getNodeType(), NodeEnum.processing.getType())
                                && !currentNodes.contains(e.getNodeCode()) && finalHistoric.contains(e.getNodeCode()))
                        .map(TemplateNodeEntity::getNodeCode).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(processingList)) {
                    resList.addAll(processingList);
                }
            }
        }

        return resList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 辅助信息 添加归档文件信息
     */
    public void setFlowFile(NodeModel currentNode, TaskEntity taskEntity, Map<String, Object> nodeProperties) {
        List<AuxiliaryInfo> auxiliaryList = currentNode.getAuxiliaryInfo();
        if (auxiliaryList.isEmpty()) {
            return;
        }
        long count = auxiliaryList.stream().filter(e -> ObjectUtil.equals(e.getConfig().getOn(), 0)).count();
        if (count == auxiliaryList.size()) {
            nodeProperties.put("auxiliaryInfo", null);
            return;
        }
        AuxiliaryInfo auxiliary = auxiliaryList.stream().filter(e -> ObjectUtil.equals(e.getId(), 3)).findFirst()
                .orElse(null);
        if (null == auxiliary) {
            return;
        }
        AuxiliaryInfoConfig auxiliaryConfig = auxiliary.getConfig();
        if (!ObjectUtil.equals(auxiliaryConfig.getOn(), 1)) {
            return;
        }
        String templateId = taskEntity.getTemplateId();
        FlowFileModel flowFileModel = FlowFileModel.builder().templateId(templateId)
                .userId(UserProvider.getLoginUserId())
                .dataRange(auxiliaryConfig.getDataRange()).build();
        List<Map<String, Object>> flowFile = serviceUtil.getFlowFile(flowFileModel);
        if (CollectionUtil.isEmpty(flowFile)) {
            return;
        }
        Object auxiliaryInfo = nodeProperties.get("auxiliaryInfo");
        if (auxiliaryInfo instanceof List) {
            List<Map<String, Object>> list = (List<Map<String, Object>>) auxiliaryInfo;
            for (Map<String, Object> map : list) {
                if (ObjectUtil.equals(map.get("id"), 3)) {
                    Map<String, Object> config = (Map<String, Object>) map.get("config");
                    config.put("fileList", flowFile);
                }
            }
        }
    }
}
