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

import cn.axzo.workflow.core.service.support.forecast.AbstractForecast;
import com.google.common.collect.Lists;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.SequenceFlow;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 顺序流节点预测唯一一条通路
 *
 * @author wangli
 * @since 2023/10/10 10:28
 */
@Component
public class SequenceFlowForecasting extends AbstractForecast<SequenceFlow> {

    @Override
    public Boolean support(FlowElement flowElement) {
        return flowElement instanceof SequenceFlow;
    }

    @Override
    protected List<? extends FlowElement> getOutgoing(SequenceFlow flowElement) {
        return Lists.newArrayList(flowElement.getTargetFlowElement());
    }

    @Override
    public List<? extends FlowElement> calcRealOutgoingNodes(List<SequenceFlow> flowElements,
                                                             String processInstanceId) {
        if (CollectionUtils.isEmpty(flowElements)) {
            return Collections.emptyList();
        }

        // 评估顺序流集合中条件为 true 的顺序流
        List<SequenceFlow> executableFlows =
                flowElements.stream().filter(i -> StringUtils.hasLength(i.getConditionExpression()))
                        .filter(i -> conditionOn(i.getConditionExpression(), processInstanceId)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(executableFlows) && executableFlows.size() == 1) {
            return Lists.newArrayList(executableFlows.get(0));
        }

        // 如果 conditionExpression 为空, 则认为是默认流
        List<SequenceFlow> defaultFlows =
                flowElements.stream().filter(i -> Objects.isNull(i.getConditionExpression())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(defaultFlows) && defaultFlows.size() == 1) {
            return Lists.newArrayList(defaultFlows.get(0));
        }
        return super.calcRealOutgoingNodes(flowElements, processInstanceId);
    }
}
