package com.wx.application.nebula.graph.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wx.application.core.entity.GraphCase;
import com.wx.application.core.mapper.GraphCaseMapper;
import com.wx.application.nebula.graph.base.BaseGraphSerice;
import com.wx.application.nebula.graph.query.NebulaModel;
import com.wx.application.nebula.graph.query.NebulaNode;
import com.wx.application.nebula.graph.query.NebulaQo;
import com.wx.application.nebula.graph.query.NebulaRelation;
import com.wx.application.nebula.graph.query.PageRequest;
import com.wx.application.nebula.graph.query.TermQuery;
import com.wx.application.nebula.graph.query.TermQueryBuilder;

import cn.hutool.json.JSONObject;

@Service
public class NebulaOperateService extends BaseGraphSerice {
	
	@Autowired
	GraphCaseMapper graphCaseMapper;
	
	/**
	 * 查询所有图空间
	 * @param space
	 * @param nQ
	 * @return
	 */
	public List<JSONObject> findSpace() {
		
		List<JSONObject> spaces = showSpace();
		List<JSONObject> result = new ArrayList<>();
		spaces.forEach(v-> {
			
			String sn = v.getStr("Name");
			if("dn_noumenon_space".equals(sn)) {
				return;
			}
			
			QueryWrapper<GraphCase> wrapper = new QueryWrapper();
			wrapper.eq("name", sn);
			GraphCase graphCase = graphCaseMapper.selectOne(wrapper);
			JSONObject st = descSpace(v.getStr("Name"));
			
			if(graphCase != null) {
				st.set("comment", graphCase.getComment());
				st.set("OntologyId", graphCase.getOntologyId());
			}
			
			result.add(st);
		});
		return result;
	}
	
	
	public NebulaModel findPathInSpace(String space, NebulaQo nQ) {
		
		long sttime = System.currentTimeMillis();
		nQ.setPageSize(50);
		
        PageRequest pageRequest = PageRequest.of(0, nQ.getPageSize());
		List<NebulaNode> nodes = findNodes(space, pageRequest);
        
        long edtime = System.currentTimeMillis();
        
        /**
         * 根据点查询一个点的周边
         */
        
        if(nodes.size() == 0) {
        	return null;
        }
        
        int i = 0;
        ExecutorService executor = Executors.newFixedThreadPool(nodes.size());
        
        
        Set<NebulaNode> nodeset = new HashSet<>();
    	Set<NebulaRelation> relationset = new HashSet<>();
        
    	
    	//效果2
        for(NebulaNode node : nodes) {
        	executor.submit(new Runnable() {
                @Override
                public void run() {
                	NebulaModel nml = findOnePathById(space, node.getVid());
                	nodeset.addAll(nml.getNodes());
                	relationset.addAll(nml.getRelations()); 
                }
    		});
        }
        
        executor.shutdown();
        try {
			if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
			    
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
        
        edtime = System.currentTimeMillis();
        System.out.println("耗时" + (edtime-sttime) );
        
        if(relationset.size() > 200) {
        	
        	Set<NebulaNode> nodeset1 = new HashSet<>();
        	Set<NebulaRelation> relationset1 = new HashSet<>();
        	
        	Map<String, NebulaNode> nodeMap = nodeset.stream().
        			collect(Collectors.toMap(NebulaNode::getVid, a -> a,(k1,k2)->k1));
        	i=0;
        	
        	for(NebulaRelation rt : relationset) {
        		relationset1.add(rt);
        		nodeset1.add(nodeMap.get(rt.getSrcId()));
        		nodeset1.add(nodeMap.get(rt.getDstId()));
        		i++;
        		if(i >= 200) {
        			break;
        		}
        	}
        	
        	NebulaModel result = new NebulaModel();
            result.setNodes(new ArrayList<>(nodeset1));
            result.setRelations(new ArrayList<>(relationset1));
            return result;
        }

        NebulaModel result = new NebulaModel();
        result.setNodes(new ArrayList<>(nodeset));
        result.setRelations(new ArrayList<>(relationset));
        return result;
	}
	

	/**
	 * 根据tag查询点
	 */
	public List<NebulaNode> findNodes(String space, NebulaQo nQ) {
		if(StringUtils.isBlank(nQ.getTag())) {
			return null;
		}
		PageRequest pageRequest = PageRequest.of(0, nQ.getPageSize());
		List<NebulaNode> ns = findNodes(space, nQ.getTag(), null, pageRequest);
		return ns;
	}
	
	/**
	 * 根据edge查询
	 */
	public NebulaModel findRelations(String space, NebulaQo nQ) {
		
		if(StringUtils.isBlank(nQ.getEdge())) {
			return null;
		}
		
		PageRequest pageRequest = PageRequest.of(0, 100);
		List<NebulaRelation> relations = findRelations(space, nQ.getEdge(), null, pageRequest);
		
		List<NebulaNode> nodes = new Vector<>();
		
		List<JSONObject> tags =showTag(space, false);
		List<String> tagList = new ArrayList<>();
		
		for(JSONObject tg : tags) {
    		String tag = tg.getStr("Name");
    		tagList.add(tag);
		}
		
		Set<String> vidset = new HashSet<>();
		
		for(NebulaRelation rel : relations) {
			vidset.add(rel.getSrcId());
			vidset.add(rel.getDstId());
		}
		
		List<String> vids = new ArrayList<>();
		ExecutorService executor = Executors.newFixedThreadPool(10);
		
		for(String vid : vidset) {
			vids.add(vid);
			if(vids.size() >= 50) {
				List<String> vidsThread = new ArrayList<>(vids);
				executor.submit(new Runnable() {
	                @Override
	                public void run() {
	                	List<NebulaNode> ns = findNodeByIds(space, StringUtils.join(tagList,","), vidsThread);
	                	nodes.addAll(ns);
	                }
	    		});
				vids.clear();
			}
		}
		
		if(vids.size() > 0) {
			executor.submit(new Runnable() {
                @Override
                public void run() {
                	List<NebulaNode> ns = findNodeByIds(space, StringUtils.join(tagList,","), vids);
                	nodes.addAll(ns);
                }
    		});
        }
		
		executor.shutdown();
        try {
			if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
			    
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
        
        NebulaModel result = new NebulaModel();
        result.setNodes(nodes);
        result.setRelations(relations);
        return result;
	}
	
	
	
	/**
	 * 根据
	 * @param space
	 * @param tag
	 * @param pageRequest
	 * @return
	 */
	public List<NebulaNode> findNodeByKeyword(String space, String tag, NebulaQo nQ) {
		
		if(StringUtils.isBlank(nQ.getKeyword())) {
			return null;
		}
		
		TermQueryBuilder builder = new TermQueryBuilder();
    	builder.add(TermQueryBuilder.termMust(nQ.getField(), TermQuery.Operator.STARTSWITH, nQ.getKeyword()));
    	/**
    	 * 查询模型的节点
    	 */
    	
    	PageRequest pageRequest = PageRequest.of(0, nQ.getPageSize());
    	
		return findNodesByWhere(space, tag, builder, pageRequest);
	}
	
	/**
	 * 按图空间进行统计
	 */
	public List<JSONObject> censusGraphBySpace(String space) {
		
		List<JSONObject> rs = showStats(space);
		if(rs.size() > 0) {
			return rs;
		}
		
		Integer jobId = submitJobStats(space);
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
		}
		
		if(jobId != null) {
			rs = showStats(space);
			//stopJob(space, jobId);
		}
		return rs;
	}
}
