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

import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNodeProperty;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignApproverLimit;
import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowableListener;
import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.BaseExecutionListener;
import org.flowable.engine.delegate.TaskListener;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

import static cn.axzo.workflow.common.code.ConvertorRespCode.CONVERTOR_COMMON_ERROR;
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
import static cn.axzo.workflow.common.constant.BpmnConstants.AUTO_APPROVAL_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_ACTIVITY_SIGNATURE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_MODE_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_SCOPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_SPECIFY;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE_SPECIFY_COOPERATE_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE_SPECIFY_RANGE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE_SPECIFY_RANGE_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE_SPECIFY_RANGE_UNIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_AREA_FILTER_ENABLE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CARBON_COPY;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CURRENT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_HISTORY;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_PERMISSION;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_LEADER_RANGE_UNIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_COOPERATE_TYPES;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_IDENTITY_TYPES;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_FILTER;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_RANGE;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ROLE_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SPECIALTY_FILTER_ENABLE;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_APPROVER_SPECIFY;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CHECKED;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION_ONLY_ONE;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_CONF;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_SIGN;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
import static cn.axzo.workflow.core.common.utils.BpmnJsonConverterUtil.buildMetaButton;
import static org.flowable.bpmn.model.ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION;

/**
 * 用户任务节点
 *
 * @author wangli
 * @since 2023/10/13 17:01
 */
public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {

    @Override
    public UserTask convertJsonToElement(BpmnJsonNode node, Process process, String formKey) {
        UserTask userTask = new UserTask();

        userTask.setId(node.getId());
        userTask.setName(node.getName());
        userTask.setFormKey(formKey);

        // 设置会签或签
        setMultiInstance(node, userTask);
        // 设置全局任务监听器
        setTaskListeners(userTask);
        // 设置全局执行监听器
        setExecutionListeners(node, userTask);

        //以下是保存配置信息, 引擎完全不会 care 这里的信息
        // "设置审批人"
        setApprovalExtensionElement(node, userTask);
        // "表单权限设置"
        setFormFieldExtensionElement(node, userTask);
        // "高级设置",包含按钮配置,自动过审配置
        setAdvancedExtensionElement(node, userTask);
        // "待办消息模板配置"
        setPendingMessageExtensionElement(node, userTask);

        // 如果审批人为空时,同时选择了自动通过, 则设置跳过表达式, 但由于使用 Flowable 框架变量操作不当会引起后续节点异常,
        // 所以统一通过 AutoOperatorEvent_101_Listener 类解决自动操作
        // setEmptyAssigneeAutoPassed(node, userTask);
        return userTask;
    }

    private static void setPendingMessageExtensionElement(BpmnJsonNode node, UserTask userTask) {
        BpmnJsonNodeProperty property = node.getProperty();
        if (Objects.isNull(property) || Objects.isNull(property.getPending())) {
            return;
        }
        ExtensionElement pendingMessageElement = new ExtensionElement();
        pendingMessageElement.setName(TEMPLATE_PENDING_MESSAGE_ID);
        ExtensionAttribute pendingMessageAttribute = new ExtensionAttribute();
        pendingMessageAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
        pendingMessageAttribute.setValue(property.getPending().getPendingMessageId());
        pendingMessageElement.addAttribute(pendingMessageAttribute);
        pendingMessageElement.setElementText(StringUtils.hasText(property.getPending().getViewJson()) ?
                property.getPending().getViewJson() : "");
        userTask.addExtensionElement(pendingMessageElement);
    }

    private static void setMultiInstance(BpmnJsonNode node, UserTask userTask) {
        if (Objects.isNull(node.getProperty()) || Objects.equals(NODE_STARTER.getType(), userTask.getId())
                || Objects.equals(Boolean.FALSE, node.getProperty().getIsMultiTask())) {
            return;
        }
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics =
                new MultiInstanceLoopCharacteristics();
        // 审批人集合参数
        multiInstanceLoopCharacteristics.setInputDataItem(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + userTask.getId());
        // 迭代集合
        multiInstanceLoopCharacteristics.setElementVariable("assigneeName");
        // 并行
        multiInstanceLoopCharacteristics.setSequential(node.getProperty().getIsSequential());
        userTask.setAssignee("${assigneeName}");
        // 设置多实例属性
        userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);

        // 设置会签或签
        if (BpmnFlowNodeMode.OR.equals(node.getProperty().getMultiMode())) {
            multiInstanceLoopCharacteristics.setCompletionCondition(OR_SIGN_EXPRESSION_ONLY_ONE);
        } else if (BpmnFlowNodeMode.AND.equals(node.getProperty().getMultiMode())) {
            multiInstanceLoopCharacteristics.setCompletionCondition(AND_SIGN_EXPRESSION);
        }
    }

    private static void setAdvancedExtensionElement(BpmnJsonNode node, UserTask userTask) {
        if (Objects.isNull(node.getProperty()) || Objects.isNull(node.getProperty().getButtonPermission())) {
            return;
        }
        BpmnButtonConf buttonConf = node.getProperty().getButtonPermission();
        ExtensionElement buttonConfigElement = new ExtensionElement();
        buttonConfigElement.setName(CONFIG_BUTTON);

        if (Objects.nonNull(buttonConf)) {
            buildMetaButton(buttonConf.getInitiator(), CONFIG_BUTTON_TYPE_INITIATOR, buttonConfigElement);
            buildMetaButton(buttonConf.getCurrent(), CONFIG_BUTTON_TYPE_CURRENT, buttonConfigElement);
            buildMetaButton(buttonConf.getHistory(), CONFIG_BUTTON_TYPE_HISTORY, buttonConfigElement);
            buildMetaButton(buttonConf.getCarbonCopy(), CONFIG_BUTTON_TYPE_CARBON_COPY, buttonConfigElement);
        }
        userTask.addExtensionElement(buttonConfigElement);

        ExtensionElement areaFilterEnableElement = new ExtensionElement();
        areaFilterEnableElement.setName(CONFIG_AREA_FILTER_ENABLE);
        ExtensionAttribute areaFilterEnableAttribute = new ExtensionAttribute();
        areaFilterEnableAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED);
        areaFilterEnableAttribute.setValue(String.valueOf(Boolean.TRUE.equals(node.getProperty().getAreaFilterEnable())));
        areaFilterEnableElement.addAttribute(areaFilterEnableAttribute);
        userTask.addExtensionElement(areaFilterEnableElement);

        ExtensionElement specialtyFilterEnableElement = new ExtensionElement();
        specialtyFilterEnableElement.setName(CONFIG_SPECIALTY_FILTER_ENABLE);
        ExtensionAttribute specialtyFilterEnableAttribute = new ExtensionAttribute();
        specialtyFilterEnableAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED);
        specialtyFilterEnableAttribute.setValue(String.valueOf(Boolean.TRUE.equals(node.getProperty().getSpecialtyFilterEnable())));
        specialtyFilterEnableElement.addAttribute(specialtyFilterEnableAttribute);
        userTask.addExtensionElement(specialtyFilterEnableElement);

        //添加自动审批配置
        ExtensionElement autoApprovalExtensionElement = new ExtensionElement();
        ExtensionAttribute pendingMessageAttribute = new ExtensionAttribute();
        pendingMessageAttribute.setName(AUTO_APPROVAL_TYPE);
        autoApprovalExtensionElement.addAttribute(pendingMessageAttribute);
        userTask.addExtensionElement(autoApprovalExtensionElement);
    }

    private static void setFormFieldExtensionElement(BpmnJsonNode node, UserTask userTask) {
        if (Objects.isNull(node.getProperty()) || CollectionUtils.isEmpty(node.getProperty().getFieldPermission())) {
            return;
        }
        ExtensionElement fieldElement = new ExtensionElement();
        fieldElement.setName(CONFIG_FIELD_PERMISSION);
        fieldElement.setElementText(Objects.nonNull(node.getProperty().getFieldPermission()) ?
                JSON.toJSONString(node.getProperty().getFieldPermission()) : null);
        userTask.addExtensionElement(fieldElement);
    }

    private static void setApprovalExtensionElement(BpmnJsonNode node, UserTask userTask) {
        BpmnJsonNodeProperty property = node.getProperty();
        if (Objects.isNull(property)) {
            return;
        }

        if (Objects.nonNull(property.getApprovalMethod())) {
            // 审批方式
            ExtensionElement approvalMethodElement = new ExtensionElement();
            approvalMethodElement.setName(CONFIG_APPROVAL_METHOD);

            ExtensionAttribute approvalMethodValueAttribute = new ExtensionAttribute();
            approvalMethodValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approvalMethodValueAttribute.setValue(property.getApprovalMethod().getType());
            approvalMethodElement.addAttribute(approvalMethodValueAttribute);

            ExtensionAttribute approvalMethodDescAttribute = new ExtensionAttribute();
            approvalMethodDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approvalMethodDescAttribute.setValue("审批方式");
            approvalMethodElement.addAttribute(approvalMethodDescAttribute);
            userTask.addExtensionElement(approvalMethodElement);
        }

        if (BpmnFlowNodeType.NODE_BUSINESS.equals(node.getType()) && ApprovalMethodEnum.nobody.equals(property.getApprovalMethod())) {
            // 业务节点有一种不设置审批人的选项, 除"审批方式"外都是空配置, 所以在此直接中断后续的扩展属性配置
            return;
        }

        // 签署确认节点特有的配置
        BpmnSignApproverLimit signApproverLimit = property.getSignApproverLimit();
        if (Objects.equals(NODE_SIGN, node.getType()) && Objects.nonNull(signApproverLimit)
                && Objects.nonNull(signApproverLimit.getOrgLimit()) && Objects.nonNull(signApproverLimit.getRoleLimit())) {
            ExtensionElement signApproveElement = new ExtensionElement();
            signApproveElement.setName(CONFIG_SIGN_APPROVER_LIMIT);

            ExtensionElement signApproverOrgLimitElement = new ExtensionElement();
            signApproverOrgLimitElement.setName(CONFIG_SIGN_APPROVER_ORG_LIMIT);
            ExtensionAttribute signApproverOrgLimitValueAttribute = new ExtensionAttribute();
            signApproverOrgLimitValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            signApproverOrgLimitValueAttribute.setValue(signApproverLimit.getOrgLimit().getType());
            ExtensionAttribute signApproverOrgLimitDescAttribute = new ExtensionAttribute();
            signApproverOrgLimitDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            signApproverOrgLimitDescAttribute.setValue(signApproverLimit.getOrgLimit().getDesc());
            signApproverOrgLimitElement.addAttribute(signApproverOrgLimitValueAttribute);
            signApproverOrgLimitElement.addAttribute(signApproverOrgLimitDescAttribute);
            signApproveElement.addChildElement(signApproverOrgLimitElement);

            ExtensionElement signApproverRoleLimitElement = new ExtensionElement();
            signApproverRoleLimitElement.setName(CONFIG_SIGN_APPROVER_ROLE_LIMIT);
            ExtensionAttribute signApproverRoleLimitValueAttribute = new ExtensionAttribute();
            signApproverRoleLimitValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            signApproverRoleLimitValueAttribute.setValue(signApproverLimit.getRoleLimit().getType());
            ExtensionAttribute signApproverRoleLimitDescAttribute = new ExtensionAttribute();
            signApproverRoleLimitDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            signApproverRoleLimitDescAttribute.setValue(signApproverLimit.getRoleLimit().getDesc());
            signApproverRoleLimitElement.addAttribute(signApproverRoleLimitValueAttribute);
            signApproverRoleLimitElement.addAttribute(signApproverRoleLimitDescAttribute);
            signApproveElement.addChildElement(signApproverRoleLimitElement);

            userTask.addExtensionElement(signApproveElement);

            if (Objects.isNull(property.getApproverSpecify())) {
                property.setApproverSpecify(ApproverSpecifyEnum.signerRelated);
            }
        }

        // TODO 签署确认节点的一些额外配置，需要在此处处理。
        if (Objects.nonNull(property.getApproverScope())) {
            // 审批人所在范围
            ExtensionElement approverScopeElement = new ExtensionElement();
            approverScopeElement.setName(CONFIG_APPROVER_SCOPE);

            ExtensionAttribute approverScopeValueAttribute = new ExtensionAttribute();
            approverScopeValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approverScopeValueAttribute.setValue(property.getApproverScope().getType());
            approverScopeElement.addAttribute(approverScopeValueAttribute);

            ExtensionAttribute approverScopeDescAttribute = new ExtensionAttribute();
            approverScopeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approverScopeDescAttribute.setValue("审批人所在范围");
            approverScopeElement.addAttribute(approverScopeDescAttribute);
            userTask.addExtensionElement(approverScopeElement);
        }

        if (Objects.nonNull(property.getApproverSpecify())) {

            // 审批人指定
            ExtensionElement approverSpecifyElement = new ExtensionElement();
            approverSpecifyElement.setName(CONFIG_APPROVER_SPECIFY);

            ExtensionAttribute approverSpecifyValueAttribute = new ExtensionAttribute();
            approverSpecifyValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approverSpecifyValueAttribute.setValue(property.getApproverSpecify().getType());
            approverSpecifyElement.addAttribute(approverSpecifyValueAttribute);
            ExtensionAttribute approverSpecifyDescAttribute = new ExtensionAttribute();
            approverSpecifyDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approverSpecifyDescAttribute.setValue("审批人指定");
            approverSpecifyElement.addAttribute(approverSpecifyDescAttribute);

            if (property.getApproverSpecify().name().contains("_v2")) {
                switch (property.getApproverSpecify()) {
                    case position_v2:
                        if (Objects.isNull(property.getApproverSpecifyRange())) {
                            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "缺少岗位的二级配置");
                        }
                        ExtensionElement approverSpecifyRangePosition = new ExtensionElement();
                        approverSpecifyRangePosition.setName(CONFIG_APPROVE_SPECIFY_RANGE);

                        ExtensionAttribute approverSpecifyRangeAttribute = new ExtensionAttribute();
                        approverSpecifyRangeAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                        approverSpecifyRangeAttribute.setValue(property.getApproverSpecifyRange().getType());
                        approverSpecifyRangePosition.addAttribute(approverSpecifyRangeAttribute);

                        ExtensionAttribute approverSpecifyRangeDescAttribute = new ExtensionAttribute();
                        approverSpecifyRangeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                        approverSpecifyRangeDescAttribute.setValue(property.getApproverSpecifyRange().getDesc());
                        approverSpecifyRangePosition.addAttribute(approverSpecifyRangeDescAttribute);

                        switch (property.getApproverSpecifyRange()) {
                            case within_the_project_construction_units:
                                if (Objects.isNull(property.getCooperateShipType())) {
                                    throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "岗位“项目内岗位”缺少级联配置");
                                }
                                ExtensionElement cooperateShipType = new ExtensionElement();
                                cooperateShipType.setName(CONFIG_APPROVE_SPECIFY_COOPERATE_TYPE);
                                ExtensionAttribute cooperateShipTypeAttribute = new ExtensionAttribute();
                                cooperateShipTypeAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                                cooperateShipTypeAttribute.setValue(property.getCooperateShipType().name());
                                cooperateShipType.addAttribute(cooperateShipTypeAttribute);

                                ExtensionAttribute cooperateShipTypeDescAttribute = new ExtensionAttribute();
                                cooperateShipTypeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                                cooperateShipTypeDescAttribute.setValue(property.getCooperateShipType().getDesc());
                                cooperateShipType.addAttribute(cooperateShipTypeDescAttribute);
                                approverSpecifyElement.addChildElement(cooperateShipType);

                                ExtensionElement approverSpecifyRangeUnit = new ExtensionElement();
                                approverSpecifyRangeUnit.setName(CONFIG_APPROVE_SPECIFY_RANGE_UNIT);
                                ExtensionAttribute approverSpecifyRangeUnitAttribute = new ExtensionAttribute();
                                approverSpecifyRangeUnitAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                                approverSpecifyRangeUnitAttribute.setValue(property.getApproverSpecifyRangeUnit().getType());
                                approverSpecifyRangeUnit.addAttribute(approverSpecifyRangeUnitAttribute);

                                ExtensionAttribute approverSpecifyRangeUnitDescAttribute = new ExtensionAttribute();
                                approverSpecifyRangeUnitDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                                approverSpecifyRangeUnitDescAttribute.setValue(property.getApproverSpecifyRangeUnit().getDesc());
                                approverSpecifyRangeUnit.addAttribute(approverSpecifyRangeUnitDescAttribute);
                                approverSpecifyElement.addChildElement(approverSpecifyRangeUnit);
                                break;
                            case specified_org:
                                checkCascadeConfig(property, "岗位“审批单指定的末级组织”");
                                addCascadeConfig(property, approverSpecifyElement);
                                break;
                            case initiator:
                                checkCascadeConfig(property, "岗位“审批单发起人”");
                                addCascadeConfig(property, approverSpecifyElement);
                                break;
                            case pre_node_approver:
                                checkCascadeConfig(property, "岗位“上节点审批人”");
                                addCascadeConfig(property, approverSpecifyElement);
                                break;
                            default:
                                break;
                        }
                        approverSpecifyElement.addChildElement(approverSpecifyRangePosition);
                        break;
                    case role_v2:
                        if (Objects.isNull(property.getApproverSpecifyRange())) {
                            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "缺少角色的二级配置");
                        }
                        ExtensionElement approverSpecifyRangeRole = new ExtensionElement();
                        approverSpecifyRangeRole.setName(CONFIG_APPROVE_SPECIFY_RANGE);
                        ExtensionAttribute approverSpecifyRangeRoleAttribute = new ExtensionAttribute();
                        approverSpecifyRangeRoleAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                        approverSpecifyRangeRoleAttribute.setValue(property.getApproverSpecifyRange().getType());
                        approverSpecifyRangeRole.addAttribute(approverSpecifyRangeRoleAttribute);

                        ExtensionAttribute approverSpecifyRangeRoleDescAttribute = new ExtensionAttribute();
                        approverSpecifyRangeRoleDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                        approverSpecifyRangeRoleDescAttribute.setValue(property.getApproverSpecifyRange().getDesc());
                        approverSpecifyRangeRole.addAttribute(approverSpecifyRangeRoleDescAttribute);
                        switch (property.getApproverSpecifyRange()) {
                            case within_the_project_construction_units:
                                if (Objects.isNull(property.getCooperateShipType())) {
                                    throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "角色“项目内角色”缺少级联配置");
                                }
                                ExtensionElement cooperateShipType = new ExtensionElement();
                                cooperateShipType.setName(CONFIG_APPROVE_SPECIFY_COOPERATE_TYPE);
                                ExtensionAttribute cooperateShipTypeAttribute = new ExtensionAttribute();
                                cooperateShipTypeAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                                cooperateShipTypeAttribute.setValue(property.getCooperateShipType().name());
                                cooperateShipType.addAttribute(cooperateShipTypeAttribute);

                                ExtensionAttribute cooperateShipTypeDescAttribute = new ExtensionAttribute();
                                cooperateShipTypeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                                cooperateShipTypeDescAttribute.setValue(property.getCooperateShipType().getDesc());
                                cooperateShipType.addAttribute(cooperateShipTypeDescAttribute);

                                approverSpecifyElement.addChildElement(cooperateShipType);
                                break;
                            case specified_org:
                                checkCascadeConfig(property, "角色“审批单指定的末级组织”");
                                addCascadeConfig(property, approverSpecifyElement);
                                break;
                            case initiator:
                                checkCascadeConfig(property, "角色“审批单发起人”");
                                addCascadeConfig(property, approverSpecifyElement);
                                break;
                            case pre_node_approver:
                                checkCascadeConfig(property, "角色“上节点审批人”");
                                addCascadeConfig(property, approverSpecifyElement);
                                break;
                            default:
                                break;
                        }
                        approverSpecifyElement.addChildElement(approverSpecifyRangeRole);
                        break;
                    case identity_v2:
                        if (Objects.isNull(property.getApproverSpecifyRange())) {
                            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "缺少身份的二级配置");
                        }
                        ExtensionElement approverSpecifyRangeIdentity = new ExtensionElement();
                        approverSpecifyRangeIdentity.setName(CONFIG_APPROVE_SPECIFY_RANGE);
                        ExtensionAttribute approverSpecifyRangeIdentityAttribute = new ExtensionAttribute();
                        approverSpecifyRangeIdentityAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                        approverSpecifyRangeIdentityAttribute.setValue(property.getApproverSpecifyRange().getType());
                        approverSpecifyRangeIdentity.addAttribute(approverSpecifyRangeIdentityAttribute);

                        ExtensionAttribute approverSpecifyRangeIdentityDescAttribute = new ExtensionAttribute();
                        approverSpecifyRangeIdentityDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                        approverSpecifyRangeIdentityDescAttribute.setValue(property.getApproverSpecifyRange().getDesc());
                        approverSpecifyRangeIdentity.addAttribute(approverSpecifyRangeIdentityDescAttribute);

                        switch (property.getApproverSpecifyRange()) {
                            case within_the_project_construction_units:
                                throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "身份不支持“项目内参建单位的企业身份”选项");
                            case specified_org:
                                checkCascadeConfig(property, "身份“审批单指定的末级组织”", false);
                                addCascadeConfig(property, approverSpecifyElement, false);
                                break;
                            case initiator:
                                checkCascadeConfig(property, "身份“审批单发起人”", false);
                                addCascadeConfig(property, approverSpecifyElement, false);
                                break;
                            case pre_node_approver:
                                checkCascadeConfig(property, "身份“上节点审批人”", false);
                                addCascadeConfig(property, approverSpecifyElement, false);
                                break;
                            default:
                                break;
                        }
                        approverSpecifyElement.addChildElement(approverSpecifyRangeIdentity);
                        break;
                    case initiatorSpecified_v2:
                        if (Objects.isNull(property.getInitiatorSpecifyRange())) {
                            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "缺少发起人自选的二级配置");
                        }
                        ExtensionElement initiatorSpecifyRange = new ExtensionElement();
                        initiatorSpecifyRange.setName(CONFIG_INITIATOR_SPECIFIED_RANGE);

                        ExtensionAttribute initiatorSpecifyRangeAttribute = new ExtensionAttribute();
                        initiatorSpecifyRangeAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                        initiatorSpecifyRangeAttribute.setValue(property.getInitiatorSpecifyRange().getType());
                        initiatorSpecifyRange.addAttribute(initiatorSpecifyRangeAttribute);

                        ExtensionAttribute initiatorSpecifyRangeDescAttribute = new ExtensionAttribute();
                        initiatorSpecifyRangeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                        initiatorSpecifyRangeDescAttribute.setValue(property.getInitiatorSpecifyRange().getDesc());
                        initiatorSpecifyRange.addAttribute(initiatorSpecifyRangeDescAttribute);

                        approverSpecifyElement.addChildElement(initiatorSpecifyRange);

                        boolean enableFilter = Boolean.TRUE.equals(property.getInitiatorSpecifiedFilter());
                        ExtensionElement InitiatorSpecifiedFilter = new ExtensionElement();
                        InitiatorSpecifiedFilter.setName(CONFIG_INITIATOR_SPECIFIED_FILTER);
                        ExtensionAttribute InitiatorSpecifiedFilterAttribute = new ExtensionAttribute();
                        InitiatorSpecifiedFilterAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                        InitiatorSpecifiedFilterAttribute.setValue(String.valueOf(enableFilter));
                        InitiatorSpecifiedFilter.addAttribute(InitiatorSpecifiedFilterAttribute);

                        ExtensionAttribute InitiatorSpecifiedFilterDescAttribute = new ExtensionAttribute();
                        InitiatorSpecifiedFilterDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                        InitiatorSpecifiedFilterDescAttribute.setValue("是否开起发起人的筛选策略");
                        InitiatorSpecifiedFilter.addAttribute(InitiatorSpecifiedFilterDescAttribute);
                        approverSpecifyElement.addChildElement(InitiatorSpecifiedFilter);

                        if (enableFilter) {
                            ExtensionElement excludeIdentityTypes = new ExtensionElement();
                            excludeIdentityTypes.setName(CONFIG_INITIATOR_SPECIFIED_EXCLUDE_IDENTITY_TYPES);
                            excludeIdentityTypes.setElementText(JSON.toJSONString(
                                    CollectionUtils.isEmpty(property.getExcludeIdentityTypes()) ? new ArrayList<>() : property.getExcludeIdentityTypes())
                            );
                            approverSpecifyElement.addChildElement(excludeIdentityTypes);

                            ExtensionElement excludeCooperateShipTypes = new ExtensionElement();
                            excludeCooperateShipTypes.setName(CONFIG_INITIATOR_SPECIFIED_EXCLUDE_COOPERATE_TYPES);
                            excludeCooperateShipTypes.setElementText(JSON.toJSONString(
                                    CollectionUtils.isEmpty(property.getExcludeCooperateShipTypes()) ? new ArrayList<>() : property.getExcludeCooperateShipTypes())
                            );
                            approverSpecifyElement.addChildElement(excludeCooperateShipTypes);
                        }
                        break;
                    case initiator_v2:
                        break;
                    case initiatorLeader_v2:
                        if (Objects.isNull(property.getApproverSpecifyRangeUnit())) {
                            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "缺少发起人主管的二级配置");
                        }
                        ExtensionElement initiatorLeader = new ExtensionElement();
                        initiatorLeader.setName(CONFIG_INITIATOR_LEADER_RANGE_UNIT);
                        ExtensionAttribute initiatorLeaderAttribute = new ExtensionAttribute();
                        initiatorLeaderAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
                        initiatorLeaderAttribute.setValue(property.getApproverSpecifyRangeUnit().getType());
                        initiatorLeader.addAttribute(initiatorLeaderAttribute);

                        ExtensionAttribute initiatorLeaderDescAttribute = new ExtensionAttribute();
                        initiatorLeaderDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
                        initiatorLeaderDescAttribute.setValue(property.getApproverSpecifyRangeUnit().getDesc());
                        initiatorLeader.addAttribute(initiatorLeaderDescAttribute);
                        approverSpecifyElement.addChildElement(initiatorLeader);
                        break;
                    case fixedPerson_v2:
                        break;
                    default:
                        break;
                }
                // 审批人指定的具体值
                ExtensionElement specifyValueElement = new ExtensionElement();
                specifyValueElement.setName(TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE);
                specifyValueElement.setElementText(property.getSpecifyValue());
                approverSpecifyElement.addChildElement(specifyValueElement);
                userTask.addExtensionElement(approverSpecifyElement);
            } else {
                // 老版本的兼容
                // 审批人指定的具体值
                approverSpecifyElement.setElementText(property.getSpecifyValue());
                userTask.addExtensionElement(approverSpecifyElement);
            }
        }

        if (Objects.nonNull(property.getMultiMode())) {
            // 多人审批时审批模式
            ExtensionElement approverModeTypeElement = new ExtensionElement();
            approverModeTypeElement.setName(CONFIG_APPROVER_MODE_TYPE);

            ExtensionAttribute approverModeTypeValueAttribute = new ExtensionAttribute();
            approverModeTypeValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approverModeTypeValueAttribute.setValue(property.getMultiMode().getType());
            approverModeTypeElement.addAttribute(approverModeTypeValueAttribute);

            ExtensionAttribute approverModeTypeDescAttribute = new ExtensionAttribute();
            approverModeTypeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approverModeTypeDescAttribute.setValue("多人审批时审批模式");
            approverModeTypeElement.addAttribute(approverModeTypeDescAttribute);
            userTask.addExtensionElement(approverModeTypeElement);
        }

        if (Objects.nonNull(property.getApproverEmptyHandleType())) {
            // 审批人为空时
            ExtensionElement approverEmptyHandleTypeElement = new ExtensionElement();
            approverEmptyHandleTypeElement.setName(CONFIG_APPROVER_EMPTY_HANDLE_TYPE);
            ExtensionAttribute approverEmptyHandleTypeValueAttribute = new ExtensionAttribute();
            approverEmptyHandleTypeValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approverEmptyHandleTypeValueAttribute.setValue(property.getApproverEmptyHandleType().getType());
            approverEmptyHandleTypeElement.setElementText(StringUtils.hasLength(property.getEmptyApproverSpecify()) ?
                    property.getEmptyApproverSpecify() : "[]");
            approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeValueAttribute);

            ExtensionAttribute approverEmptyHandleTypeDescAttribute = new ExtensionAttribute();
            approverEmptyHandleTypeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approverEmptyHandleTypeDescAttribute.setValue("审批人为空时");
            approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeDescAttribute);
            userTask.addExtensionElement(approverEmptyHandleTypeElement);
        }

        if (Objects.equals(Boolean.TRUE, property.getSignature())) {
            // 电子签名开关
            ExtensionElement signatureElement = new ExtensionElement();
            signatureElement.setName(CONFIG_ACTIVITY_SIGNATURE);

            ExtensionAttribute approverSignatureValueAttribute = new ExtensionAttribute();
            approverSignatureValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approverSignatureValueAttribute.setValue(property.getSignature().toString());
            signatureElement.addAttribute(approverSignatureValueAttribute);

            ExtensionAttribute approverSignatureDescAttribute = new ExtensionAttribute();
            approverSignatureDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approverSignatureDescAttribute.setValue("电子签名");
            signatureElement.addAttribute(approverSignatureDescAttribute);

            userTask.addExtensionElement(signatureElement);
        }

        // “提级审批配置”
        BpmnUpgradeApprovalConf upgradeApprovalConf = property.getUpgradeApprovalConf();
        if (Objects.nonNull(upgradeApprovalConf) && Objects.equals(Boolean.TRUE, upgradeApprovalConf.getEnabled())) {
            ExtensionElement upgradeApprovalElement = new ExtensionElement();
            upgradeApprovalElement.setName(TEMPLATE_UPGRADE_APPROVAL_CONF);
            ExtensionAttribute upgradeApprovalEnabledAttribute = new ExtensionAttribute();
            upgradeApprovalEnabledAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED);
            upgradeApprovalEnabledAttribute.setValue(String.valueOf(Boolean.TRUE.equals(property.getUpgradeApprovalConf().getEnabled())));
            upgradeApprovalElement.addAttribute(upgradeApprovalEnabledAttribute);


            ExtensionElement upgradeApprovalLimitElement = new ExtensionElement();
            upgradeApprovalLimitElement.setName(TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF);

            ExtensionAttribute upgradeApprovalLimitOrgAttribute = new ExtensionAttribute();
            upgradeApprovalLimitOrgAttribute.setName(ELEMENT_ATTRIBUTE_ORG_LIMIT);
            upgradeApprovalLimitOrgAttribute.setValue(property.getUpgradeApprovalConf().getOrgLimit().getType());
            upgradeApprovalLimitElement.addAttribute(upgradeApprovalLimitOrgAttribute);
            ExtensionAttribute upgradeApprovalLimitSpecifyTypeAttribute = new ExtensionAttribute();
            upgradeApprovalLimitSpecifyTypeAttribute.setName(ELEMENT_ATTRIBUTE_APPROVER_SPECIFY);
            upgradeApprovalLimitSpecifyTypeAttribute.setValue(property.getUpgradeApprovalConf().getApproverSpecify().getType());
            upgradeApprovalLimitElement.addAttribute(upgradeApprovalLimitSpecifyTypeAttribute);
            upgradeApprovalElement.addChildElement(upgradeApprovalLimitElement);

            ExtensionElement upgradeApprovalSpecifyElement = new ExtensionElement();
            upgradeApprovalSpecifyElement.setName(TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE);
            upgradeApprovalSpecifyElement.setElementText(property.getUpgradeApprovalConf().getSpecifyValue());
            upgradeApprovalElement.addChildElement(upgradeApprovalSpecifyElement);
            userTask.addExtensionElement(upgradeApprovalElement);
        }
    }

    public static void checkCascadeConfig(BpmnJsonNodeProperty property, String tips) {
        checkCascadeConfig(property, tips, true);
    }

    public static void checkCascadeConfig(BpmnJsonNodeProperty property, String tips, boolean containsRangeUnit) {
        if (Objects.isNull(property.getApproverSpecifyRangeOrgLimit())) {
            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, tips + "缺少级联组织配置");
        }
        if (Objects.isNull(property.getApproverSpecifyRangeUnit()) && containsRangeUnit) {
            throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, tips + "缺少级联配置");
        }
    }

    private static void addCascadeConfig(BpmnJsonNodeProperty property, ExtensionElement parentElement) {
        addCascadeConfig(property, parentElement, true);
    }

    /**
     * 添加级联配置协议转换
     *
     * @param property
     * @param parentElement
     */
    private static void addCascadeConfig(BpmnJsonNodeProperty property, ExtensionElement parentElement, boolean containsRangeUnit) {
        ExtensionElement specifiedOrg = new ExtensionElement();
        specifiedOrg.setName(CONFIG_APPROVE_SPECIFY_RANGE_ORG_LIMIT);
        ExtensionAttribute specifiedOrgAttribute = new ExtensionAttribute();
        specifiedOrgAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
        specifiedOrgAttribute.setValue(property.getApproverSpecifyRangeOrgLimit().name());
        specifiedOrg.addAttribute(specifiedOrgAttribute);

        ExtensionAttribute specifiedOrgDescAttribute = new ExtensionAttribute();
        specifiedOrgDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
        specifiedOrgDescAttribute.setValue(property.getApproverSpecifyRangeOrgLimit().getDesc());
        specifiedOrg.addAttribute(specifiedOrgDescAttribute);
        parentElement.addChildElement(specifiedOrg);

        if (containsRangeUnit) {
            ExtensionElement approverSpecifyRangeUnit = new ExtensionElement();
            approverSpecifyRangeUnit.setName(CONFIG_APPROVE_SPECIFY_RANGE_UNIT);
            ExtensionAttribute approverSpecifyRangeUnitAttribute = new ExtensionAttribute();
            approverSpecifyRangeUnitAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
            approverSpecifyRangeUnitAttribute.setValue(property.getApproverSpecifyRangeUnit().getType());
            approverSpecifyRangeUnit.addAttribute(approverSpecifyRangeUnitAttribute);

            ExtensionAttribute approverSpecifyRangeUnitDescAttribute = new ExtensionAttribute();
            approverSpecifyRangeUnitDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC);
            approverSpecifyRangeUnitDescAttribute.setValue(property.getApproverSpecifyRangeUnit().getDesc());
            approverSpecifyRangeUnit.addAttribute(approverSpecifyRangeUnitDescAttribute);
            parentElement.addChildElement(approverSpecifyRangeUnit);
        }
    }

    /**
     * 设置执行监听
     *
     * @param node
     * @param userTask
     */
    private static void setExecutionListeners(BpmnJsonNode node, UserTask userTask) {

        List<FlowableListener> executionListeners = new ArrayList<>();
        // 设置执行监听
        FlowableListener executionListener = new FlowableListener();
        executionListener.setEvent(BaseExecutionListener.EVENTNAME_START);
        executionListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
        executionListener.setImplementation("${engineExecutionStartListener}");
        executionListeners.add(executionListener);

        if (!Objects.equals(NODE_STARTER, node.getType())) {
            FlowableListener activityStartListener = new FlowableListener();
            activityStartListener.setEvent(BaseExecutionListener.EVENTNAME_START);
            activityStartListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
            activityStartListener.setImplementation("${engineActivityStartEventListener}");
            executionListeners.add(activityStartListener);

            // take 事件在 Flowable 引擎中只针对 SequenceFlow 有效，所以这里不设置 take 事件
            /*FlowableListener activityTakeListener = new FlowableListener();
            activityTakeListener.setEvent(BaseExecutionListener.EVENTNAME_TAKE);
            activityTakeListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
            activityTakeListener.setImplementation("${engineActivityTakeEventListener}");
            executionListeners.add(activityTakeListener);*/

            FlowableListener activityEndListener = new FlowableListener();
            activityEndListener.setEvent(BaseExecutionListener.EVENTNAME_END);
            activityEndListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
            activityEndListener.setImplementation("${engineActivityEndEventListener}");
            executionListeners.add(activityEndListener);
        }

        userTask.setExecutionListeners(executionListeners);
    }

    /**
     * 设置任务监听
     *
     * @param userTask
     */
    private static void setTaskListeners(UserTask userTask) {
        List<FlowableListener> taskListeners = new ArrayList<>();
        // 设置任务监听
        FlowableListener taskListener = new FlowableListener();
        taskListener.setEvent(TaskListener.EVENTNAME_ALL_EVENTS);
        taskListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);

        taskListener.setImplementation("${engineTaskEventListener}");
        taskListeners.add(taskListener);

        userTask.setTaskListeners(taskListeners);
    }

}
