package cn.axzo.workflow.core.converter.json;

import cn.axzo.workflow.common.model.request.bpmn.BpmnCondition;
import cn.axzo.workflow.common.model.request.bpmn.BpmnConditionGroup;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNodeProperty;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.SequenceFlow;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;

import static cn.axzo.workflow.common.constant.BpmnConstants.SEQUENCE_FLOW_ID;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CONDITION;
import static cn.axzo.workflow.core.common.utils.BpmnExpressionTranslator.translateCheckbox;
import static cn.axzo.workflow.core.common.utils.BpmnExpressionTranslator.translateNumber;
import static cn.axzo.workflow.core.common.utils.BpmnExpressionTranslator.translateRadio;
import static cn.axzo.workflow.core.common.utils.BpmnExpressionTranslator.translateString;
import static cn.axzo.workflow.core.common.utils.BpmnJsonConverterUtil.id;

/**
 * 顺序流节点
 *
 * @author wangli
 * @since 2023/10/13 18:45
 */
public class SequenceFlowJsonConverter extends AbstractBpmnJsonConverter<SequenceFlow> {

    @Override
    public SequenceFlow convertJsonToElement(BpmnJsonNode node, Process process) {
        List<String> incoming = node.getIncoming();
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId(id(SEQUENCE_FLOW_ID));
        sequenceFlow.setName(node.getName());
        sequenceFlow.setSourceRef(incoming.get(0));
        sequenceFlow.setTargetRef(node.getId());

        // 设置条件表达式
        setConditionExpression(node, sequenceFlow);
        return sequenceFlow;
    }

    /**
     * 设置条件表达式
     *
     * @param node
     * @param sequenceFlow
     */
    private void setConditionExpression(BpmnJsonNode node, SequenceFlow sequenceFlow) {
        BpmnJsonNode preJsonNode = node.getPreJsonNode();
        if (Objects.isNull(preJsonNode) || !NODE_CONDITION.equals(preJsonNode.getType())
                || CollectionUtils.isEmpty(preJsonNode.getProperty().getGroups())
                || (preJsonNode.getProperty().getGroups().size() == 1 && CollectionUtils.isEmpty(preJsonNode.getProperty().getGroups().get(0).getConditions()))) {
            return;
        }

        BpmnJsonNodeProperty nodeProperty = preJsonNode.getProperty();
        List<BpmnConditionGroup> groups = nodeProperty.getGroups();
        StringBuilder sb = new StringBuilder("${");
        groups.forEach(group -> {
            String operator = "||";
            if ("and".equalsIgnoreCase(nodeProperty.getGroupsType())) {
                operator = "&&";
            }
            if (sb.indexOf(operator) > 0 || sb.length() != 2) {
                sb.append(" ").append(operator).append(" ");
            }
            StringBuilder conditionSb = new StringBuilder();
            if (!CollectionUtils.isEmpty(group.getConditions())) {
                conditionSb.append("(");
                group.getConditions().forEach(condition -> {
                    String conditionOperator = "||";
                    if ("and".equalsIgnoreCase(group.getConditionsType())) {
                        conditionOperator = "&&";
                    }
                    if (conditionSb.indexOf(conditionOperator) > 0 || conditionSb.length() != 1) {
                        conditionSb.append(" ").append(conditionOperator).append(" ");
                    }
                    conditionSb.append(parseConditions(condition));
                });
                conditionSb.append(")");
            }
            sb.append(conditionSb);
        });
        sb.append("}");
        sequenceFlow.setConditionExpression(sb.toString());
    }

    private String parseConditions(BpmnCondition condition) {
        String expression = null;
        switch (condition.getType()) {
            case "number":
                expression = translateNumber(condition);
                break;
            case "radio":
                expression = translateRadio(condition);
                break;
            case "checkbox":
                expression = translateCheckbox(condition);
                break;
            default:
                // String
                expression = translateString(condition);
                break;
        }
        return expression;
    }

}
