package com.yunzhupaas.flowable.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.emnus.SearchMethodEnum;
import com.yunzhupaas.emnus.TemplateEnum;
import com.yunzhupaas.flowable.entity.RecordEntity;
import com.yunzhupaas.flowable.entity.TaskEntity;
import com.yunzhupaas.flowable.enums.NodeEnum;
import com.yunzhupaas.flowable.model.task.FlowMethod;
import com.yunzhupaas.flowable.model.templatejson.FlowParamModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.GroupsModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.NodeModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.ProperCond;
import com.yunzhupaas.flowable.model.templatenode.nodejson.TemplateJsonModel;
import com.yunzhupaas.permission.entity.UserEntity;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/4/18 20:22
 */

public class FlowJsonUtil {

    /**
     * 节点条件判断
     **/
    public static boolean nodeConditionDecide(FlowMethod flowMethod) {
        List<ProperCond> conditionList = flowMethod.getConditions();
        String matchLogic = flowMethod.getMatchLogic();
        boolean flag = false;
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("js");
        Map<String, Object> map = flowMethod.getFormData();
        List<String> expressionAll = new ArrayList<>();
        StringBuilder condition = new StringBuilder();
        for (int k = 0; k < conditionList.size(); k++) {
            StringBuilder expression = new StringBuilder();
            expression.append("(");
            ProperCond properCond = conditionList.get(k);
            String logic = properCond.getLogic();
            List<GroupsModel> groups = properCond.getGroups();
            for (int i = 0; i < groups.size(); i++) {
                GroupsModel groupsModel = groups.get(i);
                String contain = "!=-1";
                String field = groupsModel.getField();
                String yunzhupaasKey = groupsModel.getYunzhupaasKey();
                int fieldType = groupsModel.getFieldType();
                Object form = fieldType == 1 ? formValue(flowMethod, yunzhupaasKey, map.get(field))
                        : formula(groupsModel, map);
                Object formValue = form;
                String symbol = groupsModel.getSymbol();
                boolean include = ("like".equals(symbol) || "notLike".equals(symbol));
                if ("<>".equals(symbol)) {
                    symbol = "!=";
                }
                int fieldValueType = groupsModel.getFieldValueType();
                String valueYunzhupaasKey = StringUtil.isNotEmpty(groupsModel.getFieldValueYunzhupaasKey())
                        ? groupsModel.getFieldValueYunzhupaasKey()
                        : yunzhupaasKey;
                Object filedData = groupsModel.getFieldValue();

                Object value;
                if (fieldValueType == 3 || fieldValueType == 4) {

                    TemplateJsonModel templateJsonModel = new TemplateJsonModel();
                    templateJsonModel.setField(groupsModel.getField());
                    templateJsonModel.setSourceType(fieldValueType == 3 ? 4 : TemplateEnum.Field.getCode());
                    templateJsonModel.setMsgTemplateId(groupsModel.getField());
                    templateJsonModel.setRelationField(String.valueOf(groupsModel.getFieldValue()));

                    MsgUtil msgUtil = new MsgUtil();
                    TaskEntity flowTaskEntity = flowMethod.getTaskEntity();

                    Map<String, Object> mapData = new HashMap<>();
                    if (null != flowTaskEntity) {
                        if (StringUtil.isNotEmpty(flowTaskEntity.getGlobalParameter())) {
                            mapData = JsonUtil.stringToMap(flowTaskEntity.getGlobalParameter());
                        }
                    }
                    if (CollectionUtil.isEmpty(mapData)) {
                        NodeModel global = flowMethod.getNodes().get(NodeEnum.global.getType());
                        if (null != global) {
                            List<FlowParamModel> paramModelList = global.getGlobalParameterList();
                            for (FlowParamModel model : paramModelList) {
                                mapData.put(model.getFieldName(), model.getDefaultValue());
                            }
                        }
                    }

                    List<TemplateJsonModel> list = new ArrayList<>();
                    list.add(templateJsonModel);

                    RecordEntity record = new RecordEntity();
                    record.setNodeCode(flowMethod.getNodeCode());
                    UserEntity createUser = flowMethod.getCreateUser();
                    UserEntity delegate = flowMethod.getDelegate();
                    Map<String, String> resMap = msgUtil.parameterMap(mapData, list, record, flowTaskEntity, createUser,
                            delegate);
                    value = resMap.get(field);
                    if (value != null) {
                        value = "'" + value + "'";
                    }
                } else {
                    value = fieldValueType == 2 ? filedValue(flowMethod, filedData, valueYunzhupaasKey, form)
                            : filedData(flowMethod, filedData, valueYunzhupaasKey, form);
                }
                Object fieldValue = value;
                String pression = formValue + symbol + fieldValue;
                // 比较的处理
                if ("<=".equals(symbol) || "<".equals(symbol) || ">".equals(symbol) || ">=".equals(symbol)) {
                    try {
                        String formValueStr = formValue.toString();
                        if (formValueStr.startsWith("'") && formValueStr.endsWith("'")) {
                            formValueStr = formValueStr.substring(1, formValueStr.length() - 1);
                        }
                        fieldValue = fieldValue == null ? "" : fieldValue;
                        String fieldValueStr = fieldValue.toString();
                        if (fieldValueStr.startsWith("'") && fieldValueStr.endsWith("'")) {
                            fieldValueStr = fieldValueStr.substring(1, fieldValueStr.length() - 1);
                        }
                        BigDecimal a = new BigDecimal(formValueStr);
                        BigDecimal b = new BigDecimal(fieldValueStr);
                        boolean res = false;
                        if ("<=".equals(symbol)) {
                            res = a.compareTo(b) <= 0;
                        } else if ("<".equals(symbol)) {
                            res = a.compareTo(b) < 0;
                        } else if (">".equals(symbol)) {
                            res = a.compareTo(b) > 0;
                        } else if (">=".equals(symbol)) {
                            res = a.compareTo(b) >= 0;
                        }
                        pression = res + "";
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                        pression = "false";
                    }
                }
                if (include) {
                    if ("notLike".equals(symbol)) {
                        contain = "==-1";
                    }
                    symbol = ".indexOf";
                    if (!(formValue instanceof CharSequence)) {
                        formValue = "'" + formValue + "'";
                    }
                    if (!(fieldValue instanceof CharSequence)) {
                        fieldValue = "'" + fieldValue + "'";
                    }
                    pression = formValue + ".toString()" + symbol + "(" + fieldValue + ")" + contain;
                }
                if (ObjectUtil.equals(symbol, "null")) {
                    pression = "(" + formValue + " == null || " + formValue + " == '')";
                }
                if (ObjectUtil.equals(symbol, "notNull")) {
                    pression = "(" + formValue + " != null && " + formValue + " != '')";
                }
                expression.append(pression);
                if (!StringUtils.isEmpty(logic) && i != groups.size() - 1) {
                    expression.append(" " + search(logic) + " ");
                }
            }
            expression.append(")");
            expressionAll.add(expression.toString());
        }
        for (int i = 0; i < expressionAll.size(); i++) {
            String script = expressionAll.get(i);
            String search = i != expressionAll.size() - 1 ? search(matchLogic) : "";
            condition.append(script + " " + search + " ");
        }
        try {
            flag = (Boolean) scriptEngine.eval(condition.toString());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return flag;
    }

    /**
     * 条件表达式
     *
     * @param logic
     */
    private static String search(String logic) {
        return SearchMethodEnum.And.getSymbol().equalsIgnoreCase(logic) ? "&&" : "||";
    }

    /**
     * 条件数据修改
     *
     * @param flowMethod
     * @param value
     */
    private static Object filedValue(FlowMethod flowMethod, Object value, String yunzhupaasKey, Object form) {
        UserInfo userInfo = flowMethod.getUserInfo();
        if ("currentUser".equals(value)) {
            value = userInfo.getUserId();
        }
        try {
            try {
                List<List<String>> dataAll = JsonUtil.getJsonToBean(value, List.class);
                List<String> id = new ArrayList<>();
                for (List<String> data : dataAll) {
                    id.addAll(data);
                }
                value = String.join(",", id);
            } catch (Exception e) {
                try {
                    List<String> id = new ArrayList<>();
                    List<String> dataAll = JsonUtil.getJsonToList(value, String.class);
                    if (YunzhupaasKeyConsts.CURRORGANIZE.equals(yunzhupaasKey)) {
                        value = dataAll.stream().filter(t -> ("'" + t + "'").equals(form)).findFirst().orElse(null);
                    } else {
                        for (String data : dataAll) {
                            id.add(data);
                        }
                        value = String.join(",", id);
                    }
                } catch (Exception e1) {

                }
            }
        } catch (Exception e) {

        }
        if (value instanceof CharSequence) {
            value = "'" + value + "'";
        }
        return value;
    }

    /**
     * 条件数据修改
     *
     * @param flowMethod
     * @param value
     */
    private static Object filedData(FlowMethod flowMethod, Object value, String yunzhupaasKey, Object form) {
        Map<String, Object> map = flowMethod.getFormData();
        value = map.get(value);
        UserEntity userEntity = flowMethod.getUserEntity();
        TaskEntity taskEntity = flowMethod.getTaskEntity();
        try {
            try {
                List<List<String>> dataAll = JsonUtil.getJsonToBean(value, List.class);
                List<String> id = new ArrayList<>();
                for (List<String> data : dataAll) {
                    id.addAll(data);
                }
                value = String.join(",", id);
            } catch (Exception e) {
                try {
                    List<String> id = new ArrayList<>();
                    List<String> dataAll = JsonUtil.getJsonToList(value, String.class);
                    if (YunzhupaasKeyConsts.CURRORGANIZE.equals(yunzhupaasKey)
                            || YunzhupaasKeyConsts.COMSELECT.equals(yunzhupaasKey)) {
                        value = dataAll.stream().filter(t -> ("'" + t + "'").equals(form)).findFirst().orElse(null);
                    } else {
                        for (String data : dataAll) {
                            id.add(data);
                        }
                        value = String.join(",", id);
                    }
                } catch (Exception e1) {

                }
            }
            if (YunzhupaasKeyConsts.CREATETIME.equals(yunzhupaasKey)) {
                Date creatorTime = taskEntity.getCreatorTime();
                value = null == creatorTime ? null : creatorTime.getTime();
            } else if (YunzhupaasKeyConsts.CREATEUSER.equals(yunzhupaasKey)) {
                value = taskEntity.getCreatorUserId();
            } else if (YunzhupaasKeyConsts.CURRORGANIZE.equals(yunzhupaasKey)) {
                value = userEntity.getOrganizeId();
            } else if (YunzhupaasKeyConsts.CURRPOSITION.equals(yunzhupaasKey)) {
                value = userEntity.getPositionId();
            } else if (YunzhupaasKeyConsts.MODIFYTIME.equals(yunzhupaasKey)) {
                Date lastModifyTime = taskEntity.getLastModifyTime();
                value = null == lastModifyTime ? null : lastModifyTime.getTime();
            } else if (YunzhupaasKeyConsts.MODIFYUSER.equals(yunzhupaasKey)) {
                value = taskEntity.getLastModifyUserId();
            }
        } catch (Exception e) {

        }
        if (value instanceof CharSequence) {
            value = "'" + value + "'";
        }
        return value;
    }

    /**
     * 表单数据修改
     *
     * @param form
     */
    private static Object formValue(FlowMethod flowMethod, String yunzhupaasKey, Object form) {
        Object result = form;
        UserEntity userEntity = flowMethod.getUserEntity();
        TaskEntity flowTaskEntity = flowMethod.getTaskEntity();
        try {
            try {
                List<List<String>> dataAll = JsonUtil.getJsonToBean(form, List.class);
                List<String> id = new ArrayList<>();
                for (List<String> data : dataAll) {
                    id.addAll(data);
                }
                result = String.join(",", id);
            } catch (Exception e) {
                try {
                    List<String> id = new ArrayList<>();
                    List<String> dataAll = JsonUtil.getJsonToList(form, String.class);
                    for (String data : dataAll) {
                        id.add(data);
                    }
                    result = String.join(",", id);
                } catch (Exception e1) {
                }
            }
            if (YunzhupaasKeyConsts.CREATETIME.equals(yunzhupaasKey)) {
                Date creatorTime = flowTaskEntity.getCreatorTime();
                result = null == creatorTime ? null : creatorTime.getTime();
            } else if (YunzhupaasKeyConsts.CREATEUSER.equals(yunzhupaasKey)) {
                result = StringUtil.isNotEmpty(flowTaskEntity.getDelegateUserId()) ? flowTaskEntity.getDelegateUserId()
                        : flowTaskEntity.getCreatorUserId();
            } else if (YunzhupaasKeyConsts.CURRORGANIZE.equals(yunzhupaasKey)) {
                result = userEntity.getOrganizeId();
            } else if (YunzhupaasKeyConsts.CURRPOSITION.equals(yunzhupaasKey)) {
                result = userEntity.getPositionId();
            } else if (YunzhupaasKeyConsts.MODIFYTIME.equals(yunzhupaasKey)) {
                Date lastModifyTime = flowTaskEntity.getLastModifyTime();
                result = null == lastModifyTime ? null : lastModifyTime.getTime();
            } else if (YunzhupaasKeyConsts.MODIFYUSER.equals(yunzhupaasKey)) {
                result = flowTaskEntity.getLastModifyUserId();
            }
        } catch (Exception e) {
        }
        if (result instanceof CharSequence) {
            result = "'" + result + "'";
        }
        return result;
    }

    /**
     * 表达式
     */
    private static Object formula(GroupsModel properCond, Map<String, Object> data) {
        String result = null;
        try {
            StringBuilder builder = new StringBuilder();
            builder.append("function getNum(val) {\n" +
                    "  return isNaN(val) ? 0 : Number(val)\n" +
                    "};\n" +
                    "// 求和\n" +
                    "function SUM() {\n" +
                    "  var value = 0\n" +
                    "  for (var i = 0; i < arguments.length; i++) {\n" +
                    "    value += getNum(arguments[i])\n" +
                    "  }\n" +
                    "  return value\n" +
                    "};\n" +
                    "// 求差\n" +
                    "function SUBTRACT(num1, num2) {\n" +
                    "  return getNum(num1) - getNum(num2)\n" +
                    "};\n" +
                    "// 相乘\n" +
                    "function PRODUCT() {\n" +
                    "  var value = 1\n" +
                    "  for (var i = 0; i < arguments.length; i++) {\n" +
                    "    value = value * getNum(arguments[i])\n" +
                    "  }\n" +
                    "  return value\n" +
                    "};\n" +
                    "// 相除\n" +
                    "function DIVIDE(num1, num2) {\n" +
                    "  return getNum(num1) / (getNum(num2) === 0 ? 1 : getNum(num2))\n" +
                    "};\n" +
                    "// 获取参数的数量\n" +
                    "function COUNT() {\n" +
                    "  var value = 0\n" +
                    "  for (var i = 0; i < arguments.length; i++) {\n" +
                    "    value ++\n" +
                    "  }\n" +
                    "  return value\n" +
                    "};\n");
            String field = field(properCond.getField(), data, null);
            ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
            ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("js");
            String eval = builder.toString() + " var result = " + field + ";";
            scriptEngine.eval(eval);
            double d = (double) scriptEngine.get("result");
            NumberFormat nf = NumberFormat.getNumberInstance();
            nf.setRoundingMode(RoundingMode.UP);
            result = nf.format(d);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return result;
    }

    /**
     * 替换文本值
     *
     * @param content
     * @param data
     * @return
     */
    public static String field(String content, Map<String, Object> data, String type) {
        String pattern = "[{]([^}]+)[}]";
        Pattern patternList = Pattern.compile(pattern);
        Matcher matcher = patternList.matcher(content);
        Map<String, List<String>> parameterMap = data(matcher, data);
        Map<String, Object> result = new HashMap<>();
        if (StringUtils.isNotEmpty(type)) {
            Map<String, String> datas = new HashMap<>();
            for (String key : parameterMap.keySet()) {
                datas.put(key, data.get(key) != null ? String.valueOf(data.get(key)) : "");
            }
            result.putAll(datas);
        } else {
            Map<String, Object> dataAll = new HashMap<>();
            for (String key : parameterMap.keySet()) {
                StringJoiner joiner = new StringJoiner(",");
                List<String> list = parameterMap.get(key);
                for (String id : list) {
                    joiner.add("'" + id + "'");
                }
                String value = joiner.toString();
                if (list.size() > 1) {
                    value = "SUM(" + joiner.toString() + ")";
                }
                dataAll.put(key, value);
            }
            result.putAll(dataAll);
        }
        StringSubstitutor strSubstitutor = new StringSubstitutor(result, "{", "}");
        String field = strSubstitutor.replace(content);
        return field;
    }

    /**
     * 赋值
     */
    private static Map<String, List<String>> data(Matcher matcher, Map<String, Object> dataAll) {
        Map<String, List<String>> map = new HashMap<>();
        Map<String, String> keyAll = new HashMap<>();
        while (matcher.find()) {
            String group = matcher.group().replaceAll("\\{", "").replaceAll("}", "");
            keyAll.put(group, group);
        }
        for (String id : keyAll.keySet()) {
            List<String> valueData = new ArrayList<>();
            String valueAll[] = id.split("-");
            String key = valueAll[0];
            Object childDataAll = dataAll.get(key) != null ? dataAll.get(key) : "";
            if (valueAll.length > 1) {
                String data = valueAll[1];
                if (childDataAll instanceof List) {
                    List<Map<String, Object>> childData = (List<Map<String, Object>>) childDataAll;
                    for (Map<String, Object> childDatum : childData) {
                        Object childDatas = childDatum.get(data);
                        valueData.add(childDatas + "");
                    }
                }
            } else if (valueAll.length == 1) {
                valueData.add(childDataAll + "");
            }
            map.put(id, valueData);
        }
        return map;
    }

}
