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

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.wx.application.core.entity.GraphTask;
import com.wx.application.core.service.GraphTaskService;
import com.wx.application.nebula.graph.base.Generators;
import com.wx.application.nebula.graph.bean.NebulaEdgeLine;
import com.wx.application.nebula.graph.bean.NebulaVertex;
import com.wx.application.util.MD5Util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 图谱数据导入
 */
@Slf4j
@Service
public class ImportGraphInJsonService {

    public final static String YYYYMMDD = "yyyy-MM-dd";

    @Value("${upload.graph.path}")
    private String graphFilePath;
    
    /**
     * 文件名限制
     */
    final static String vertexjson = "vertex.json";
    final static String edgejson = "edge.json";
    
    @Autowired
    GraphTaskService graphTaskService;

    @Autowired
    NebulaOperateService nebulaOperateService;
    
    /**
     * 按json文件导入
     * ---------------------------------------------------------------------------
     */
    
    /**
     * 将上传的文件zip包进行解压
     * @param space
     */
    public JSONArray uploadFile(MultipartFile file, String space) {
    	
    	JSONArray result = new JSONArray();
    	
    	/**
    	 * 这个空间有任务在执行 不能导入
    	 */
    	int c = graphTaskService.countBySpaceAndStauts(space);
    	
    	if(c > 0) {
    		return null;
    	}
    	
    	try {
    		
    		String md5Path = MD5Util.getMD5(file.getInputStream());
    		
    		String tempDir = DateUtil.format(new Date(), YYYYMMDD) + File.separator;
            String mkdir = graphFilePath + tempDir + md5Path + File.separator;
            
            if (!FileUtil.exist(mkdir)) {
                FileUtil.mkdir(mkdir);
            }

            String originalFilename = file.getOriginalFilename();
            String path = mkdir + originalFilename ;
            path = path.replaceAll("\\\\", "/");

            FileUtil.writeBytes(file.getBytes(), path);
            /**
             * 进行解压
             */
            File unzipPath = ZipUtil.unzip(path, mkdir);
            FileUtil.del(path);
            
            File[] fls = FileUtil.ls(unzipPath.getPath());
            
            JSONObject item = null;
            
            Boolean allFlag = true;
            
            for(File fn : fls) {
            	item = new JSONObject();
            	if(vertexjson.equals(fn.getName().toLowerCase())) {
            		item.set("title", "节点");
            		item.set("gf_name", vertexjson);
            		item.set("up_name", fn.getName());
            		item.set("flag", true);
            	} else if(edgejson.equals(fn.getName().toLowerCase())) {
            		item.set("title", "关系");
            		item.set("gf_name", edgejson);
            		item.set("up_name", fn.getName());
            		item.set("flag", true);
            	} else {
            		item.set("title", "匹配错误");
            		item.set("gf_name", vertexjson + "," + edgejson);
            		item.set("up_name", fn.getName());
            		item.set("flag", false);
            		allFlag = false;
            	}
            	result.add(item);
            }
            
            if(!allFlag) {
            	FileUtil.del(unzipPath.getPath());
            } else {
            	ExecutorService executor = Executors.newFixedThreadPool(1);
            	executor.submit(new Runnable() {
                    @Override
                    public void run() {
                    	beginTask(space, fls);
                    }
        		});
            	executor.shutdown();
            }
            
    	} catch (Exception e) {
			log.info("{}", e);
		}
    	return result;
    }
    
    //@Async
    public void beginTask(String space ,File[] fls) {
    	/**
    	 * 文件都匹配成功
    	 * 执行导入
    	 */
    	for(File fn : fls) {
    		if(vertexjson.equals(fn.getName().toLowerCase())) {
    			GraphTask task = new GraphTask();
    			task.setSpace(space);
    			task.setStatus(0);
    			task.setFileName(fn.getName());
    			graphTaskService.create(task);
    			analysisVertexJson(space ,fn, task.getId());
    		} else if(edgejson.equals(fn.getName().toLowerCase())) {
    			GraphTask task = new GraphTask();
    			task.setSpace(space);
    			task.setStatus(0);
    			task.setFileName(fn.getName());
    			graphTaskService.create(task);
    			analysisEdgeJson(space, fn, task.getId());
    		}
    	}
    	
    	try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
		}
    	
    	nebulaOperateService.submitJobStats(space);
    }
    
    
    public void analysisVertexJson(String space,File file, Long taskId) {
    	
    	FileReader fileReader = new FileReader(file);
		BufferedReader input = IoUtil.getUtf8Reader(fileReader.getInputStream());
		String line = null;
		List<NebulaVertex> list = new Vector<>();
		NebulaVertex vertex = null;
		try {
			while((line = input.readLine()) != null) {
				try {
					JSONObject ot = JSONUtil.parseObj(line);
					String label = ot.getStr(":LABEL");
					String id = ot.getStr(":ID");
					
					if(StringUtils.isBlank(label) || StringUtils.isBlank(id)) {
						continue;
					}
					
					String tag = Generators.tagname(label);
					JSONObject ob = new JSONObject();
					for(String key : ot.keySet()) {
						if(":LABEL".equals(key) || ":ID".equals(key)) {
							continue;
						}
						ob.set(key, ot.get(key));
					}
					if(ob.size()==0) {
						continue;
					}
					vertex = new NebulaVertex();
					vertex.setTag(tag);
					vertex.setOb(ob);
					vertex.setVid(MD5Util.MD5(id));
					
					list.add(vertex);
					
					if(list.size() > 2000) {
						log.info("执行一次 节点导入 {}", list.size());
						Map<String, List<NebulaVertex>> vMap = list.stream()
								.collect(Collectors.groupingBy(NebulaVertex::getTag));
						
						vMap.forEach((v,ls)->{
							nebulaOperateService.insertTagAll(space, v, ls);
						});
						list.clear();
					}
				} catch (Exception e) {
					log.info("{}", e.getMessage());
				} 
			}
			
			if(list.size() > 0) {
				log.info("执行一次 节点导入 {}", list.size());
				Map<String, List<NebulaVertex>> vMap = list.stream()
						.collect(Collectors.groupingBy(NebulaVertex::getTag));
				vMap.forEach((v,l)->{
					nebulaOperateService.insertTagAll(space, v, l);
				});
				vMap = null;
				list.clear();
			}
			
		} catch (IOException e) {
			log.info("{}", e);
		} finally {
			GraphTask task = new GraphTask();
			task.setId(taskId);
			task.setStatus(1);
			graphTaskService.modify(task);
		}
    }
	
    public void analysisEdgeJson(String space, File file, Long taskId) {
    	
    	FileReader fileReader = new FileReader(file);
		BufferedReader input = IoUtil.getUtf8Reader(fileReader.getInputStream());
		String line = null;
		
		List<NebulaEdgeLine> list = new Vector<>();
		
		NebulaEdgeLine edge = null;
		
		try {
			
			while((line = input.readLine()) != null) {
				
				try {
					
					JSONObject ot = JSONUtil.parseObj(line);
					String srcName = ot.getStr("头节点");
					String dctName = ot.getStr("尾节点");
					String edgeName = ot.getStr("关联");
					
					String edgeHs = Generators.edgename(edgeName);
					
					edge = new NebulaEdgeLine();
					edge.setSrcId(MD5Util.MD5(srcName));
					edge.setDstId(MD5Util.MD5(dctName));
					
					JSONObject ob = new JSONObject();
					ob.set("label", edgeName);
					edge.setOb(ob);
					edge.setEdge(edgeHs);
					list.add(edge);
					if(list.size() > 2000) {
						log.info("执行一次 关系导入 {}", list.size());
						Map<String, List<NebulaEdgeLine>> vMap = list.stream()
								.collect(Collectors.groupingBy(NebulaEdgeLine::getEdge));
						vMap.forEach((v,ls)->{
							nebulaOperateService.insertEdgeLineAll(space, v, ls);
						});
						list.clear();
					}

				} catch (Exception e) {
					log.info("{}", e.getMessage());
				} 
			}
			
			if(list.size() > 0) {
				log.info("执行一次关系导入 {}", list.size());
				Map<String, List<NebulaEdgeLine>> vMap = list.stream()
						.collect(Collectors.groupingBy(NebulaEdgeLine::getEdge));
				vMap.forEach((v,ls)->{
					nebulaOperateService.insertEdgeLineAll(space, v, ls);
				});

				list.clear();
			}
			
		} catch (IOException e) {
			log.info("{}", e);
		} finally {
			GraphTask task = new GraphTask();
			task.setId(taskId);
			task.setStatus(1);
			graphTaskService.modify(task);
		}
    }
    
}
