package cn.stylefeng.workflow.design.modular.factory;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.workflow.api.entity.design.Definition;
import cn.stylefeng.workflow.api.entity.design.Model;
import cn.stylefeng.workflow.api.entity.design.Node;
import cn.stylefeng.workflow.api.entity.design.NodeEdge;
import cn.stylefeng.workflow.api.pojo.config.SixGraphDesign;
import cn.stylefeng.workflow.api.util.Version;
import cn.stylefeng.workflow.design.modular.pojo.request.ModelRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class DefinitionFactory {

    public static Definition createNewDefinition(Model model) {
        Definition definition = new Definition();
        definition.setDefinitionId(IdWorker.getId());
        definition.setModelId(model.getModelId());
        definition.setDefinitionVersion(new Version().toString());
        return definition;
    }

    public static Definition upgradeDefinition(Definition definition) {
        Definition newDefinition = new Definition();
        newDefinition.setDefinitionId(IdWorker.getId());
        newDefinition.setModelId(definition.getModelId());

        Version version = new Version(definition.getDefinitionVersion());
        version.upgrade();

        newDefinition.setDefinitionVersion(version.toString());
        return newDefinition;
    }

    public static Model createCopyNewModel(Model originModel, ModelRequest modelRequest) {

        originModel.setModelId(IdWorker.getId());

        String modelName = modelRequest.getModelName();
        if (StrUtil.isNotBlank(modelName)) {
            originModel.setModelName(modelName);
        } else {
            originModel.setModelName(originModel.getModelName() + "_" + originModel.getModelId());
        }

        originModel.setModelCode(originModel.getModelCode() + "_" + originModel.getModelId());

        originModel.setFldSort(originModel.getFldSort().add(new BigDecimal("1")));

        return originModel;
    }

    public static Definition createCopyNewDefinition(Definition originDefinition, Long newModelId) {

        originDefinition.setDefinitionId(IdWorker.getId());
        originDefinition.setModelId(newModelId);
        originDefinition.setDefinitionVersion(new Version().toString());

        SixGraphDesign xSixGraphJson = originDefinition.getXSixGraphJson();
        if (ObjectUtil.isEmpty(xSixGraphJson)) {
            return originDefinition;
        }

        JSONObject newJsonObject = DefinitionFactory.createReplaceIdNewX6GraphDesign(xSixGraphJson);
        xSixGraphJson.setNodeGraph(newJsonObject);
        originDefinition.setXSixGraphJson(xSixGraphJson);

        return originDefinition;
    }

    public static JSONObject createReplaceIdNewX6GraphDesign(SixGraphDesign xSixGraphJson) {

        List<Long> x6NodeIdList = DefinitionFactory.getX6NodeIdList(xSixGraphJson);
        List<Long> x6EdgeIdList = DefinitionFactory.getX6EdgeIdList(xSixGraphJson);

        JSONObject nodeGraph = xSixGraphJson.getNodeGraph();

        String nodeGraphJsonString = nodeGraph.toJSONString();

        String regex = "\\b\\d{19}\\b";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(nodeGraphJsonString);

        HashMap<String, String> oldIdNewIdMap = new HashMap<>();
        while (matcher.find()) {

            String idStr = matcher.group();

            if (!oldIdNewIdMap.containsKey(idStr)) {

                if (!x6NodeIdList.contains(Long.valueOf(idStr)) && !x6EdgeIdList.contains(Long.valueOf(idStr))) {
                    continue;
                }

                String newIdStr = String.valueOf(IdWorker.getId());
                oldIdNewIdMap.put(idStr, newIdStr);
            }
        }

        for (String oldId : oldIdNewIdMap.keySet()) {
            String newId = oldIdNewIdMap.get(oldId);
            nodeGraphJsonString = nodeGraphJsonString.replaceAll(oldId, newId);
        }

        return JSON.parseObject(nodeGraphJsonString);
    }

    public static List<Long> getX6NodeIdList(SixGraphDesign sixGraphDesign) {
        if (ObjectUtil.isEmpty(sixGraphDesign)) {
            return new ArrayList<>();
        }
        if (ObjectUtil.isEmpty(sixGraphDesign.getNodeGraph())) {
            return new ArrayList<>();
        }

        List<Node> nodes = GraphFactory.parseX6NodeList(new Definition(), sixGraphDesign.getNodeGraph());
        if (ObjectUtil.isEmpty(nodes)) {
            return new ArrayList<>();
        }

        return nodes.stream().map(Node::getNodeId).collect(Collectors.toList());
    }

    public static List<Long> getX6EdgeIdList(SixGraphDesign sixGraphDesign) {
        if (ObjectUtil.isEmpty(sixGraphDesign)) {
            return new ArrayList<>();
        }
        if (ObjectUtil.isEmpty(sixGraphDesign.getNodeGraph())) {
            return new ArrayList<>();
        }

        List<NodeEdge> edgeList = GraphFactory.parseX6EdgeList(new Definition(), sixGraphDesign.getNodeGraph());
        if (ObjectUtil.isEmpty(edgeList)) {
            return new ArrayList<>();
        }

        return edgeList.stream().map(NodeEdge::getEdgeId).collect(Collectors.toList());
    }

}
