package com.tofly.analyse.service.impl;


import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.supermap.data.*;
import com.tofly.analyse.entity.LayerFiledConfig;
import com.tofly.analyse.entity.Pipeline;
import com.tofly.analyse.entity.em.LayerTypeEnum;
import com.tofly.analyse.entity.em.PipeLineQueryEnum;
import com.tofly.analyse.entity.em.PipeNodeQueryEnum;
import com.tofly.analyse.mapper.PipelineMapper;
import com.tofly.analyse.service.LayerFiledConfigService;
import com.tofly.analyse.service.PipelineService;
import com.tofly.analyse.util.analysis.CamelToUtil;
import com.tofly.analyse.util.analysis.DatasourceConfig;
import com.tofly.common.core.entity.ResultRespone;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author zhoux
 */
@AllArgsConstructor
@Service("pipelineService")
public class PipelineServiceImpl extends ServiceImpl<PipelineMapper, Pipeline> implements PipelineService {

    @Autowired
    private PipelineMapper pipelineMapper;

    @Autowired
    private LayerFiledConfigService layerFiledConfigService;

    @Autowired
    private DatasourceConfig datasourceConfig;

    /**
     * 管线追踪性分析业务方法
     */
    @Override
    public Map<String, Object> getPipelineConnect(Map<String, String> pipeParams) {
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> edges = new ArrayList<>();
        List<Object> nodes = new ArrayList<>();
        List<Map<String, Object>> returnList = new ArrayList<>();
        LayerFiledConfig layfiledConfig = layerFiledConfigService.getOne(Wrappers.<LayerFiledConfig>query().lambda().eq(LayerFiledConfig::getLayerName, pipeParams.get("tableName")));
        if (layfiledConfig != null) {
            String sp = CamelToUtil.underlineToCamel(layfiledConfig.getSPoint());
            String ep = CamelToUtil.underlineToCamel(layfiledConfig.getEPoint());
            String no = CamelToUtil.underlineToCamel(layfiledConfig.getNo());
            String dr = CamelToUtil.underlineToCamel(layfiledConfig.getDirFlow());

            Map<String, String> queryMap = new HashMap<String, String>();
            queryMap.put("pipePointNo", pipeParams.get("pipePointNo"));
            queryMap.put("tableName", pipeParams.get("tableName"));
            queryMap.put("no", layfiledConfig.getNo());
            if(StringUtils.isNotBlank(dr)){
                queryMap.put("dir", layfiledConfig.getDirFlow());
            }
            queryMap.put("sPoint", layfiledConfig.getSPoint());
            queryMap.put("ePoint", layfiledConfig.getEPoint());
            List<Map<String, Object>> gisInfo = pipelineMapper.getPipeInfos(queryMap);
            if (gisInfo.size() != 0) {
                returnList.addAll(gisInfo);
                Map<String, Object> pipeInfo = gisInfo.get(0);
                String sPoint = null;
                String ePonit = null;
                String drs =null;
                if(StringUtils.isNotBlank(dr)){
                     drs = pipeInfo.get(dr).toString();
                }
                if (pipeParams.get("tableName").contains("PS")) {
                    if (drs.equals("0")) {
                        sPoint = pipeInfo.get(sp).toString();
                        ePonit = pipeInfo.get(ep).toString();
                    } else {
                        sPoint = pipeInfo.get(ep).toString();
                        ePonit = pipeInfo.get(sp).toString();
                    }
                } else {
                    sPoint = pipeInfo.get(sp).toString();
                    ePonit = pipeInfo.get(ep).toString();
                }
                String lno = pipeInfo.get(no).toString();
                String flag = UUID.randomUUID().toString();
                String flag1 = UUID.randomUUID().toString();
                ConcurrentHashMap<String, Map<String, Object>> firstMap = new ConcurrentHashMap<String, Map<String, Object>>();
                ConcurrentHashMap<String, Map<String, Object>> secondMap = new ConcurrentHashMap<String, Map<String, Object>>();

                Map<String, Object> newValueMap = new HashMap<String, Object>();
                newValueMap.put("pathValue", new ArrayList<Map<String, Object>>());
                newValueMap.put("pathLength", 0.00);
                newValueMap.put("pathSid", lno);
                if(StringUtils.isNotBlank(dr)){
                    newValueMap.put("drs", drs);
                }
                newValueMap.put("pathStartSid", sPoint);
                firstMap.put(flag, newValueMap);

                Map<String, Object> newValue1Map = new HashMap<String, Object>();
                newValue1Map.put("pathValue", new ArrayList<Map<String, Object>>());
                newValue1Map.put("pathLength", 0.00);
                newValue1Map.put("pathSid", lno);
                if(StringUtils.isNotBlank(dr)){
                    newValue1Map.put("drs", drs);
                }
                newValue1Map.put("pathStartSid", ePonit);
                secondMap.put(flag1, newValue1Map);

                if (pipeParams.get("pipeLength") != null) {
                    Double requireLength = Double.valueOf(pipeParams.get("pipeLength")).doubleValue();
                    //获取上游追踪管线
                    checkStartConnect(requireLength, queryMap.get("tableName"), firstMap, flag, returnList, layfiledConfig);

                    //获取下游追踪管线
                    checkStartConnect(requireLength, queryMap.get("tableName"), secondMap, flag1, returnList, layfiledConfig);
                } else {
                    if (pipeParams.get("type") != null) {
                        String type = pipeParams.get("type").toString();
                        if (type.equals("0")) {
                            checkSxyConnect(type, queryMap.get("tableName"), firstMap, flag, returnList, layfiledConfig);
                        } else {
                            checkSxyConnect(type, queryMap.get("tableName"), secondMap, flag1, returnList, layfiledConfig);
                        }
                    } else {
                        //获取出水口管线
                        checkSxyConnect("1", queryMap.get("tableName"), secondMap, flag1, returnList, layfiledConfig);
                    }
                }
            }
            if (CollUtil.isNotEmpty(returnList)) {
                edges = returnList.stream().distinct().collect(Collectors.toList());
                List<String> points = new ArrayList<>();
                edges.forEach(d -> {
                    Object sPoint = d.get(sp);
                    Object ePoint = d.get(ep);
                    if (sPoint != null) {
                        String s = sPoint.toString();
                        if (!points.contains(s)) {
                            points.add(s);
                        }
                    }
                    if (ePoint != null) {
                        String s = ePoint.toString();
                        if (!points.contains(s)) {
                            points.add(s);
                        }
                    }
                });
                if (CollUtil.isNotEmpty(points)) {
                    Map<String, Object> nodeMap = new HashMap<String, Object>();
                    nodeMap.put("points", points);
                    nodeMap.put("tableName", layfiledConfig.getNodeLayerName());
                    nodeMap.put("no", layfiledConfig.getNodeNo());
                    nodeMap.put("code", layfiledConfig.getCode());
                    List<String> pointByExpNos = pipelineMapper.getPointByExpNos(nodeMap);
                    if (CollUtil.isNotEmpty(pointByExpNos)) {
                        nodes.addAll(pointByExpNos);
                    }
                }
            }
        }
        map.put("edges", edges);
        map.put("nodes", nodes);
        return map;
    }

    /**
     * 向前进行管线追踪性分析
     *
     * @param requireLength
     * @param tableName
     * @param returnMap
     * @return
     */
    public Map<String, Map<String, Object>> checkStartConnect(Double requireLength, String tableName,
                                                              ConcurrentHashMap<String, Map<String, Object>> returnMap, String pathFlag, List<Map<String, Object>> list, LayerFiledConfig layfiledConfig) {

        Map<String, Object> existPath = returnMap.get(pathFlag);
        List<Map<String, Object>> pathValue = (List<Map<String, Object>>) existPath.get("pathValue");
        Double existLength = (Double) existPath.get("pathLength");
        String pathSid = (String) existPath.get("pathSid");
        String pathStartSid = (String) existPath.get("pathStartSid");

        String sp = CamelToUtil.underlineToCamel(layfiledConfig.getSPoint());
        String ep = CamelToUtil.underlineToCamel(layfiledConfig.getEPoint());
        String no = CamelToUtil.underlineToCamel(layfiledConfig.getNo());

        Map<String, String> startMap = new HashMap<String, String>();
        startMap.put("tableName", tableName);
        startMap.put("startSid", pathStartSid);
        startMap.put("no", layfiledConfig.getNo());
        startMap.put("sPoint", layfiledConfig.getSPoint());
        startMap.put("ePoint", layfiledConfig.getEPoint());

        Boolean otherTrigger = false;

        //查找管线对应start和end节点
        List<Map<String, Object>> nextEndResult = pipelineMapper.getPipeInfos(startMap);
        List<Map<String, Object>> nextStartResult = pipelineMapper.getPipeOtherInfos(startMap);

        Iterator<Map<String, Object>> nextEndIterator = nextEndResult.iterator();
        while (nextEndIterator.hasNext()) {
            Map<String, Object> ob = nextEndIterator.next();
            if (ob.get(no).toString().equals(pathSid)) {
                nextEndIterator.remove();
            }
        }

        Iterator<Map<String, Object>> nextStartIterator = nextStartResult.iterator();
        while (nextStartIterator.hasNext()) {
            Map<String, Object> ob = nextStartIterator.next();
            if (ob.get(no).toString().equals(pathSid)) {
                nextStartIterator.remove();
            }
        }

        for (int i = 0; i < nextEndResult.size(); i++) {
            List<Map<String, Object>> newPath = new ArrayList<Map<String, Object>>();
            newPath.addAll(pathValue);
            newPath.add(nextEndResult.get(i));
            Double length = Double.valueOf(nextEndResult.get(i).get("smlength").toString()).doubleValue() + existLength;
            String sid = nextEndResult.get(i).get(no).toString();
            String startSid = null;
            if (nextEndResult.get(i).get(sp).equals(pathStartSid)) {
                startSid = nextEndResult.get(i).get(ep).toString();
            } else {
                startSid = nextEndResult.get(i).get(sp).toString();
            }
            Map<String, Object> newValueMap = new HashMap<String, Object>();
            newValueMap.put("pathValue", newPath);
            newValueMap.put("pathLength", length);
            newValueMap.put("pathSid", sid);
            newValueMap.put("pathStartSid", startSid);
            newValueMap.put("isover", "false");
            list.addAll(newPath);
            if (i == 0) {
                returnMap.put(pathFlag, newValueMap);
                otherTrigger = true;
            } else {
                returnMap.put(UUID.randomUUID().toString(), newValueMap);
            }
        }

        for (int i = 0; i < nextStartResult.size(); i++) {

            List<Map<String, Object>> newPath = new ArrayList<Map<String, Object>>();
            newPath.addAll(pathValue);
            newPath.add(nextStartResult.get(i));
            Double length = Double.valueOf(nextStartResult.get(i).get("smlength").toString()).doubleValue() + existLength;

            String sid = nextStartResult.get(i).get(no).toString();

            String startSid = null;

            if (nextStartResult.get(i).get(sp).equals(pathStartSid)) {
                startSid = nextStartResult.get(i).get(ep).toString();
            } else {
                startSid = nextStartResult.get(i).get(sp).toString();
            }

            Map<String, Object> newValueMap = new HashMap<String, Object>();

            newValueMap.put("pathValue", newPath);
            newValueMap.put("pathLength", length);
            newValueMap.put("pathSid", sid);
            newValueMap.put("pathStartSid", startSid);
            newValueMap.put("isover", "false");
            list.addAll(newPath);

            if (i == 0) {
                if (otherTrigger) {
                    returnMap.put(UUID.randomUUID().toString(), newValueMap);
                } else {
                    returnMap.put(pathFlag, newValueMap);
                }
            } else {
                returnMap.put(UUID.randomUUID().toString(), newValueMap);
            }
        }

        if (nextStartResult.size() == 0 && nextEndResult.size() == 0) {
            returnMap.get(pathFlag).put("isover", "true");
            returnMap.put(pathFlag, returnMap.get(pathFlag));
        }

        for (Map.Entry<String, Map<String, Object>> entry : returnMap.entrySet()) {
            Map<String, Object> path = entry.getValue();
            Double checkExistLength = (Double) path.get("pathLength");
            if (path.get("isover").toString().equals("false")) {
                if (checkExistLength < requireLength) {
                    checkStartConnect(requireLength, tableName, returnMap, entry.getKey(), list, layfiledConfig);
                } else {
                    continue;
                }
            }
        }
        return returnMap;
    }

    public Map<String, Map<String, Object>> checkSxyConnect(String type, String tableName,
                                                            ConcurrentHashMap<String, Map<String, Object>> returnMap, String pathFlag, List<Map<String, Object>> list, LayerFiledConfig layfiledConfig) {

        Map<String, Object> existPath = returnMap.get(pathFlag);
        List<Map<String, Object>> pathValue = (List<Map<String, Object>>) existPath.get("pathValue");
        String pathSid = (String) existPath.get("pathSid");
        String pathStartSid = (String) existPath.get("pathStartSid");

        String sp = CamelToUtil.underlineToCamel(layfiledConfig.getSPoint());
        String ep = CamelToUtil.underlineToCamel(layfiledConfig.getEPoint());
        String no = CamelToUtil.underlineToCamel(layfiledConfig.getNo());
        String model = CamelToUtil.underlineToCamel(layfiledConfig.getSubtype());
        String dr = CamelToUtil.underlineToCamel(layfiledConfig.getDirFlow());


        Map<String, Object> startMap = new HashMap<String, Object>();
        startMap.put("tableName", tableName);
        startMap.put("no", layfiledConfig.getNo());
        startMap.put("sPoint", layfiledConfig.getSPoint());
        startMap.put("ePoint", layfiledConfig.getEPoint());
        startMap.put("model", layfiledConfig.getSubtype());
        List<Map<String, Object>> nextStartResult = new ArrayList<>();
        if (tableName.contains("PS")) {
            if (type.equals("0")) {
                startMap.put("flowDir", "0");
            }else{
                startMap.put("flowDir", "1");
            }
            startMap.put("dir", layfiledConfig.getDirFlow());
            startMap.put("endSid", pathStartSid);
            startMap.put("tableNameSyNode", layfiledConfig.getNodeLayerName());
            nextStartResult = pipelineMapper.getPipeOtherInfos(startMap);
            if (type.equals("0")) {
                startMap.put("flowDir", "1");
            }else{
                startMap.put("flowDir", "0");
            }
            startMap.put("startSid", pathStartSid);
            startMap.put("endSid", null);
            startMap.put("tableNameSyNode", null);
            startMap.put("tableNameNode", layfiledConfig.getNodeLayerName());
            List<Map<String, Object>> pipeOtherInfos = pipelineMapper.getPipeOtherInfos(startMap);
            nextStartResult.addAll(pipeOtherInfos);
        } else {
            if (type.equals("0")) {
                startMap.put("endSid", pathStartSid);
                startMap.put("tableNameSyNode", layfiledConfig.getNodeLayerName());
            } else {
                startMap.put("startSid", pathStartSid);
                startMap.put("tableNameNode", layfiledConfig.getNodeLayerName());
            }
            nextStartResult = pipelineMapper.getPipeOtherInfos(startMap);
        }

        Boolean otherTrigger = false;

        Iterator<Map<String, Object>> nextStartIterator = nextStartResult.iterator();
        while (nextStartIterator.hasNext()) {
            Map<String, Object> ob = nextStartIterator.next();
            if (ob.get(no).toString().equals(pathSid)) {
                nextStartIterator.remove();
            }
        }

        for (int i = 0; i < nextStartResult.size(); i++) {

            List<Map<String, Object>> newPath = new ArrayList<Map<String, Object>>();
            newPath.addAll(pathValue);
            newPath.add(nextStartResult.get(i));
            String sid = nextStartResult.get(i).get(no).toString();
            Object modelStr = null;
            if (nextStartResult.get(i).get(model) != null) {
                modelStr = nextStartResult.get(i).get(model);
            }

            Map<String, Object> newValueMap = new HashMap<String, Object>();

            newValueMap.put("pathValue", newPath);
            newValueMap.put("model", modelStr);
            newValueMap.put("pathSid", sid);
            String startSid=null;
            if(StringUtils.isNotBlank(dr)){
                String dirflow=nextStartResult.get(i).get(dr).toString();
                if (type.equals("0")) {
                    if(dirflow.equals("0")){
                        startSid = nextStartResult.get(i).get(sp).toString();
                    }else{
                        startSid = nextStartResult.get(i).get(ep).toString();
                    }
                }else{
                    if(dirflow.equals("0")){
                        startSid = nextStartResult.get(i).get(ep).toString();
                    }else{
                        startSid = nextStartResult.get(i).get(sp).toString();
                    }
                }
                newValueMap.put("drs",dirflow);
            }else{
                startSid =nextStartResult.get(i).get(ep).toString();
            }
            newValueMap.put("pathStartSid", startSid);
            newValueMap.put("isover", "false");
            list.addAll(newPath);

            if (i == 0) {
                if (otherTrigger) {
                    returnMap.put(UUID.randomUUID().toString(), newValueMap);
                } else {
                    returnMap.put(pathFlag, newValueMap);
                }
            } else {
                returnMap.put(UUID.randomUUID().toString(), newValueMap);
            }
        }

        if (nextStartResult.size() == 0) {
            returnMap.get(pathFlag).put("isover", "true");
            returnMap.put(pathFlag, returnMap.get(pathFlag));
        }

        for (Map.Entry<String, Map<String, Object>> entry : returnMap.entrySet()) {
            Map<String, Object> path = entry.getValue();
            Object existModel = path.get("model");
            if (path.get("isover").toString().equals("false")) {
                if (existModel != null) {
                    if (type.equals("0")) {
                        if (layfiledConfig.getSySubtypeValue().contains(existModel.toString())) {
                            continue;
                        } else {
                            checkSxyConnect(type, tableName, returnMap, entry.getKey(), list, layfiledConfig);
                        }
                    } else {
                        if (layfiledConfig.getXySubtypeValue().contains(existModel.toString())) {
                            continue;
                        } else {
                            checkSxyConnect(type, tableName, returnMap, entry.getKey(), list, layfiledConfig);
                        }
                    }
                } else {
                    checkSxyConnect(type, tableName, returnMap, entry.getKey(), list, layfiledConfig);
                }
            }
        }
        return returnMap;
    }

    @Override
    public Map<String, Object> getPointByExpNo(String expNo) {
        return baseMapper.getPointByExpNo(expNo);
    }

    @Override
    public ResultRespone getDataBykeyValue(String layerName,String keyValue) {
        List<Map<String, Object>> resultMap = new ArrayList<>();
        Workspace workspace = new Workspace();
        Datasource datasource = null;
        try {
            datasource = datasourceConfig.getDatasource(workspace);
            Datasets datasets = datasource.getDatasets();
            if(StringUtils.isNotBlank(layerName)){
                DatasetVector datasetVector = (DatasetVector) datasets.get(layerName);
                String name = datasetVector.getName();
                queryByKeyValue(keyValue, resultMap, datasetVector, name);
            }else{
                int count = datasets.getCount();
                if (count > 0) {
                    for (int i = 0; i < count; i++) {
                        DatasetVector datasetVector = (DatasetVector) datasets.get(i);
                        String name = datasetVector.getName();
                        if (datasetVector.getType() != DatasetType.NETWORK3D  && !name.contains("SM")  && name.endsWith("B") && (name.contains("NODE") || name.contains("PIPE"))) {
                            queryByKeyValue(keyValue, resultMap, datasetVector, name);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (datasource.isOpened())
                datasource.close();
            workspace.close();
        }
        return ResultRespone.success(resultMap);
    }

    private static void queryByKeyValue(String keyValue, List<Map<String, Object>> resultMap, DatasetVector datasetVector, String name) {
        Recordset recordset = datasetVector.query("(SID like '%"+ keyValue +"%') or (ADDRESS like '%"+ keyValue +"%')", CursorType.STATIC);
        recordset.moveFirst();
        while (!recordset.isEOF()) {
            Map<String,Object> dataMap=new HashMap<>();
            if(name.contains("NODE")){
                for (PipeNodeQueryEnum e : PipeNodeQueryEnum.values()){
                    Object fieldValue = recordset.getFieldValue(e.getCode());
                    dataMap.put(e.getCode(), fieldValue);
                }
                if(dataMap.get(PipeNodeQueryEnum.FTTY.getCode())!=null){
                    dataMap.put("type",LayerTypeEnum.getNameForValue(name)+dataMap.get(PipeNodeQueryEnum.FTTY.getCode()));
                }else{
                    dataMap.put("type",LayerTypeEnum.getNameForValue(name)+dataMap.get(PipeNodeQueryEnum.APTY.getCode()));
                }
            }else{
                dataMap.put("type",LayerTypeEnum.getNameForValue(name)+"管线");
                for (PipeLineQueryEnum e : PipeLineQueryEnum.values()){
                    Object fieldValue = recordset.getFieldValue(e.getCode());
                    dataMap.put(e.getCode(), fieldValue);
                }
            }
            resultMap.add(dataMap);
            recordset.moveNext();
        }
        recordset.dispose();
    }
}