package org.diagbot.service.impl;

import org.apache.commons.collections4.IterableUtils;
import org.diagbot.entity.node.LIS;
import org.diagbot.entity.node.Symptom;
import org.diagbot.mapper.KnowledgeMapper;
import org.diagbot.service.KnowledgeService;
import org.diagbot.vo.AmendRelationVo;
import org.diagbot.vo.PageVo;
import org.diagbot.vo.QueryVo;
import org.diagbot.vo.RelationVo;
import org.diagbot.entity.node.Disease;
import org.diagbot.entity.node.base.BaseNode;
import org.apache.commons.collections4.IteratorUtils;
import org.diagbot.repository.*;
import org.neo4j.driver.v1.types.Node;
import org.neo4j.driver.v1.types.Path;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

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


@Service
public class KnowledgeServiceImpl implements KnowledgeService {

    @Autowired
    private SymptomRepository symptomRepository;
    @Autowired
    private DiseaseRepository diseaseRepository;
    @Autowired
    private LISRepository lisRepository;
    @Autowired
    private BaseNodeRepository baseNodeRepository;
    @Autowired
    private RelationRepository relationRepository;
    @Autowired
    private KnowledgeMapper knowledgeMapper;

    private List<BaseNode> baseNodes;

    private Pageable pageable;
    /**
     * 处理症状节点相关的申请
     */
    @Override
    public Symptom addSymptom(Symptom symptom) {
        return symptomRepository.save(symptom);
    }

    @Override
    public Symptom findOneSymptom(long id) {
        return symptomRepository.findById(id).get();
    }

    @Override
    public List<Symptom> findSymptoms(String name) { return symptomRepository.findByNameContaining(name); }

    @Override
    public void deleteOneSymptom(long id) {
        symptomRepository.deleteById(id);
    }

    @Override
    public List<Symptom> selectAllSymptom(PageVo pageVo) {
        pageable = getPageable(pageVo);
        return IteratorUtils.toList(symptomRepository.findAll().iterator());
    }


    /**
     * 处理疾病节点相关的申请
     */
    @Override
    public Disease addDisease(Disease disease) {
        return diseaseRepository.save(disease);
    }

    @Override
    public Disease findOneDisease(long id) {
        return diseaseRepository.findById(id).get();
    }

    @Override
    public List<Disease> findDisease(String name) {
        return diseaseRepository.findByNameContaining(name);
    }

    @Override
    public void deleteOneDisease(long id) {diseaseRepository.deleteById(id); }

    @Override
    public List<Disease> selectAllDisease(PageVo pageVo) {
        pageable = getPageable(pageVo);
        return IteratorUtils.toList(diseaseRepository.findAll(pageable).iterator());
    }


    /**
     * 处理化验节点相关的申请
     */
    @Override
    public LIS addLIS(LIS lis) {
        return lisRepository.save(lis);
    }

    @Override
    public LIS findOneLIS(long id) {
        return lisRepository.findById(id).get();
    }

    @Override
    public List<LIS> findLIS(String name) { return lisRepository.findByNameContaining(name); }

    @Override
    public void deleteOneLIS(long id) {lisRepository.deleteById(id); }

    @Override
    public List<LIS> selectAllLIS(PageVo pageVo) {
        pageable = getPageable(pageVo);
        return IteratorUtils.toList(lisRepository.findAll().iterator());
    }


    @Override
    public List<Map<String, Object>> getRelationByNodes(RelationVo relationVo) {
        String s_name = relationVo.getStart_name();
        String s_type = relationVo.getStart_type();
        String e_name = relationVo.getEnd_name();
        String e_type = relationVo.getEnd_type();

        List<Map<String, Object>> list = extractPath(relationRepository.getRelationByNodes(s_name, s_type, e_name, e_type));
        return list;
    }

    @Override
    public List<Map<String, Object>> getOneLevelRelationByEndNode(RelationVo relationVo) {
        String e_name = relationVo.getEnd_name();
        String e_type = relationVo.getEnd_type();

        List<Map<String, Object>> list = extractPath(relationRepository.getOneLevelRelationByEndNode(e_name, e_type));
        return list;
    }

    @Override
    public Iterable<Map<String, Object>> getNodeByRelation(RelationVo relationVo) {
        String s_name = relationVo.getStart_name();
        String s_type = relationVo.getStart_type();
        String rel = relationVo.getRel_name();

        return relationRepository.getNodeByRelation(s_name, s_type, rel);
    }

    @Override
    public BaseNode updateNodeByName(AmendRelationVo amendRelationVo) {
        int id = amendRelationVo.getId();
        String old_name = amendRelationVo.getOld_start_name();
        String new_name = amendRelationVo.getNew_start_name();

        return baseNodeRepository.updateNodeByName(id, old_name, new_name);
    }

    @Override
    public List<Map<String, Object>> updateRelation(AmendRelationVo amendRelationVo) {
        List<Map<String, Object>> path = extractPath(knowledgeMapper.updateRelation(amendRelationVo));
        return path;
    }

    @Override
    public List<Map<String, Object>> getAllNode() {
        List<Map<String, Object>> ndlist = baseNodeRepository.getAllNode();
        return ndlist;
    }

    @Override
    public List<Map<String, Object>> findHighRiskDisease(QueryVo queryVo) {
        List<Map<String, Object>> hrlist = diseaseRepository.findHighRiskDisease(queryVo.getDiseaselist());
        return hrlist;
    }

    @Override
    public List<Map<String, Object>> getRecommendItem(QueryVo queryVo) {
        List<Map<String, Object>> llist = relationRepository.getRecommendItem(queryVo.getDiseaselist());
        return llist;
    }


    public Pageable getPageable(PageVo pageVo) {
        if (pageVo.getSize() > 0) {
            if (pageVo.getSort_key() != null && pageVo.getSort_direct() != null) {
                if (pageVo.getSort_direct().toLowerCase().equals("asc")) {
                    pageable = PageRequest.of(pageVo.getCurrent(), pageVo.getSize(),
                            Sort.Direction.ASC, pageVo.getSort_key().trim());
                }
                else if (pageVo.getSort_direct().toLowerCase().equals("desc")) {
                    pageable = PageRequest.of(pageVo.getCurrent(), pageVo.getSize(),
                            Sort.Direction.DESC, pageVo.getSort_key().trim());
                }
                else {
                    pageable = PageRequest.of(pageVo.getCurrent(), pageVo.getSize());
                }
            }
            else {
                pageable = PageRequest.of(pageVo.getCurrent(), pageVo.getSize());
            }
        }
        else {
            pageable = PageRequest.of(0, 100);
        }
        return pageable;
    }

    public List<Map<String, Object>> extractPath(Iterable<Map<String, Object>> path) {
        Map<String, Object> item = new HashMap<>();
        List<Map<String, Object>> pathlist = new ArrayList<>();
        Map<String, Object> pathmap;

        Iterator<Map<String, Object>> iterator = path.iterator();
        while (iterator.hasNext()) {
            item = iterator.next();
            pathmap = new HashMap<>();
            if (item.get("P") != null) {
                Path p = (Path)item.get("P");
                pathmap = parsePath(p);
            }
            pathlist.add(pathmap);
        }

        return pathlist;
    }

    public Map<String, Object> parsePath(Path p) {
        Map<String, Object> path = new HashMap<>();
        path.put("start", new HashMap<>());
        path.put("end", new HashMap<>());
        Map<String, String> s = (Map)path.get("start");
        Map<String, String> e = (Map)path.get("end");
        Node start = p.start();
        Node end = p.end();
        s.put("label", start.labels().iterator().next());
        e.put("label", end.labels().iterator().next());
        String relation = p.relationships().iterator().next().type();
        path.put("relation", new HashMap<>());
        ((Map)path.get("relation")).put("type", relation);

        for (String prop:start.keys()) {
            s.put(prop, start.get(prop).toString().replaceAll("\"",""));
        }

        for (String prop:end.keys()) {
            e.put(prop, end.get(prop).toString().replaceAll("\"",""));
        }

        return path;
    }

}
