package cn.stylefeng.workflow.instance.modular.task.strategy.agree.base;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.workflow.api.NodeApi;
import cn.stylefeng.workflow.api.entity.design.Node;
import cn.stylefeng.workflow.api.entity.instance.RuntimeNode;
import cn.stylefeng.workflow.api.entity.task.RuTask;
import cn.stylefeng.workflow.api.enums.ApproverNodeTypeEnum;
import cn.stylefeng.workflow.api.enums.TaskTypeEnum;
import cn.stylefeng.workflow.api.pojo.InstanceContext;
import cn.stylefeng.workflow.api.pojo.InstanceVariable;
import cn.stylefeng.workflow.api.pojo.config.node.approver.ApproverConfig;
import cn.stylefeng.workflow.api.pojo.config.node.approver.ApproverStrategy;
import cn.stylefeng.workflow.api.pojo.config.node.approver.ApproverSummary;
import cn.stylefeng.workflow.api.pojo.config.node.approver.detail.NodeApproverPerson;
import cn.stylefeng.workflow.instance.api.WorkflowStatusApi;
import cn.stylefeng.workflow.instance.modular.manage.service.RuntimeNodeService;
import cn.stylefeng.workflow.instance.modular.task.service.RuTaskService;
import cn.stylefeng.workflow.instance.modular.task.strategy.agree.BaseAgreeStrategy;

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

public class AgreeOneByOneStrategy implements BaseAgreeStrategy {

    private final boolean purePredictFlag;

    public AgreeOneByOneStrategy(boolean purePredictFlag) {
        this.purePredictFlag = purePredictFlag;
    }

    @Override
    public boolean getStrategyExecuteFlag(Integer approverNodeTypeEnum) {
        return ApproverNodeTypeEnum.ONE_BY_ONE.getMode().equals(approverNodeTypeEnum);
    }

    @Override
    public boolean strategyAction(RuTask currentProcessTask, ApproverStrategy approverStrategy) {

        RuTaskService ruTaskService = SpringUtil.getBean(RuTaskService.class);
        RuntimeNodeService runtimeNodeService = SpringUtil.getBean(RuntimeNodeService.class);
        WorkflowStatusApi workflowStatusApi = SpringUtil.getBean(WorkflowStatusApi.class);

        InstanceContext instanceContext = workflowStatusApi.buildInstanceContext(currentProcessTask.getInstanceId());

        List<Long> thisNodeTotalUserIdList = this.getPointedUserIdList(instanceContext, currentProcessTask);
        if (ObjectUtil.isEmpty(thisNodeTotalUserIdList)) {
            thisNodeTotalUserIdList = this.getFlowConfigUserIdList(currentProcessTask);
        }

        if (ObjectUtil.isEmpty(thisNodeTotalUserIdList)) {
            return false;
        }

        Long approver = currentProcessTask.getApprover();

        int currentIndex = -1;
        for (int i = 0; i < thisNodeTotalUserIdList.size(); i++) {
            if (approver.equals(thisNodeTotalUserIdList.get(i))) {
                currentIndex = i;
                break;
            }
        }

        if (currentIndex == -1) {
            return false;
        }

        int nextIndex = currentIndex + 1;

        if (nextIndex >= thisNodeTotalUserIdList.size()) {
            return true;
        }

        if (purePredictFlag) {
            return false;
        }

        Long nextUserUserId = thisNodeTotalUserIdList.get(nextIndex);

        Long ruNodeId = currentProcessTask.getRuNodeId();
        RuntimeNode runtimeNode = runtimeNodeService.getById(ruNodeId);

        ruTaskService.createUserTask(nextUserUserId, TaskTypeEnum.PROCESSING, runtimeNode, instanceContext);

        return false;
    }

    public List<Long> getPointedUserIdList(InstanceContext instanceContext, RuTask currentProcessTask) {

        InstanceVariable instanceVariable = instanceContext.getInstanceVariable();
        if (ObjectUtil.isEmpty(instanceVariable)) {
            return null;
        }

        Map<Long, List<Long>> pointNodeApproverUserId = instanceVariable.getPointNodeApproverUserId();
        if (ObjectUtil.isEmpty(pointNodeApproverUserId)) {
            return null;
        }

        List<Long> pointUserIdList = pointNodeApproverUserId.get(currentProcessTask.getReNodeId());
        if (ObjectUtil.isEmpty(pointUserIdList)) {
            return null;
        }

        return pointUserIdList;
    }

    private List<Long> getFlowConfigUserIdList(RuTask currentProcessTask) {

        NodeApi nodeApi = SpringUtil.getBean(NodeApi.class);

        Long reNodeId = currentProcessTask.getReNodeId();
        Node nodeInfo = nodeApi.getNodeInfo(reNodeId);
        if (nodeInfo == null) {
            return null;
        }

        if (nodeInfo.getNodeData() == null) {
            return null;
        }

        ApproverConfig approverConfig = nodeInfo.getNodeData().getApproverConfig();
        if (approverConfig == null) {
            return null;
        }

        ApproverSummary mainApprover = approverConfig.getMainApprover();
        if (ObjectUtil.isEmpty(mainApprover)) {
            return null;
        }

        return mainApprover.getNodeApproverPersonList().stream().map(NodeApproverPerson::getUserId).collect(Collectors.toList());
    }

}
