package com.liangjian.dataplatform.member.service.impl;

import com.liangjian.dataplatform.member.constant.MetaCoreConstant;
import com.liangjian.dataplatform.member.dao.primary.MetaCoreRepository;
import com.liangjian.dataplatform.member.dao.primary.MetaRelRepository;
import com.liangjian.dataplatform.member.entity.po.primary.MetaCore;
import com.liangjian.dataplatform.member.entity.po.primary.MetaRel;
import com.liangjian.dataplatform.member.entity.vo.MetaRelVo;
import com.liangjian.dataplatform.member.entity.vo.datanodes.*;
import com.liangjian.dataplatform.member.entity.vo.detailvo.DetailVo;
import com.liangjian.dataplatform.member.entity.vo.detailvo.PDMDetailVo;
import com.liangjian.dataplatform.member.service.DataNodeTransferService;
import com.liangjian.dataplatform.member.service.IMetaCoreCUDService;
import com.liangjian.dataplatform.member.service.IMetaCoreQueryService;
import com.liangjian.dataplatform.member.util.MetaCoreUserStuffTool;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: 黄子奇
 * @Date: 2019/8/29 13:33
 */
@Service
@Transactional
public class MetaCoreCUDService implements IMetaCoreCUDService {

    @Autowired
    private MetaCoreRepository metaCoreRepository;
    @Autowired
    private MetaRelRepository metaRelRepository;
    @Autowired
    private IMetaCoreQueryService iMetaCoreQueryService;
    @Autowired
    private DataNodeTransferService dataNodeTransferService;

    private MetaCore newOrUpdate(DataNode dataNode) {
        if(dataNode.getPrtId() == null) {
            throw new RuntimeException("not find a prtId, data error.");
        }
        MetaCore parent = null;
        if(Arrays.asList("PDM","ITF","DB","HOST").contains(dataNode.getPrtId())) {
            parent = new MetaCore();
            parent.setBizDomain(dataNode.getPrtId());
            parent.setNamespace(dataNode.getPrtId());
        } else {
            parent = metaCoreRepository.getOne(dataNode.getPrtId());
        }

        MetaCore mc = dataNode.getId() == null ?
                new MetaCore() :
                metaCoreRepository.getOne(dataNode.getId());


        mc = dataNodeTransferService.reTransfer(mc, dataNode);
        mc.setNamespace(parent.getNamespace());
        mc.setBizDomain(parent.getBizDomain());
        MetaCoreUserStuffTool.setMetaCoreCrtUser(mc);
        if(mc.getCrtDate() == null) {
            mc.setCrtDate(new Date());
        }
        mc.setLastUpdate(new Date());
        return mc;
    }

    private Boolean commonSave(MetaCore mc) {
        try{
            metaCoreRepository.save(mc);
            return true;
        } catch (Exception ex){
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean saveBasePackage(MetaCorePackage metaCorePackage) {
        MetaCore mc = newOrUpdate(metaCorePackage);
        mc.setType("pkg");
        mc.setRemarks(metaCorePackage.getRemark());
        return commonSave(mc);
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean savePDM(PDM pdm) {
        MetaCore mc = newOrUpdate(pdm);
        mc.setChName(pdm.getCnName());
        mc.setFileName(pdm.getFileName());
        mc.setRemarks(pdm.getRemark());
        return commonSave(mc);
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean savePDNColumn(PDMColumn column) {
        MetaCore mc = newOrUpdate(column);
        return commonSave(mc);
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean savePDMByDetail(PDMDetailVo detailVo) {
        //拿到Vo，先查询到原来的，进行判断哪个是需要删除，然后把新的添加
        PDM pdm = (PDM) detailVo.getRealNode();
        List<PDMColumn> newColumns = detailVo.getColumns();
        List<MetaRelVo> newRelations = detailVo.getRelations();

        try {
            if(pdm.getId() == null) {
                //新增
                MetaCore mc = newOrUpdate(pdm);
                mc = metaCoreRepository.save(mc);
                pdm.setId(mc.getId());
            }
            List<DataNode> oldColumns = iMetaCoreQueryService.queryByPrtId(pdm.getId());
            //获取需要删除的字段
            List<DataNode> need2DeleteCol = oldColumns.stream().filter(oldColumn -> {
                for (DataNode newcolumn : newColumns) {
                    if (newcolumn.getId() == null || newcolumn.getId().equals(oldColumn.getId())) {
                        return false;
                    }
                }
                return true;
            }).collect(Collectors.toList());
            //删除需要删除的字段
            for (DataNode node : need2DeleteCol) {
                metaCoreRepository.deleteById(node.getId());
            }
            //剩下的直接保存就行
            List<MetaCore> need2SaveCol = newColumns.stream()
                    .map(i -> newOrUpdate(i))
                    .peek(i -> i.setPrtId(pdm.getId()))
                    .collect(Collectors.toList());
            if(!need2SaveCol.isEmpty()) {
                metaCoreRepository.saveAll(need2SaveCol);
            }

            List<MetaRel> oldRels = metaRelRepository.queryBySrc(pdm.getId());
            //需要删除的关系
            List<MetaRel> need2DelRel = oldRels.stream().filter(oldRel -> {
                for (MetaRelVo newRelation : newRelations) {
                    if(newRelation.getRid() == null || newRelation.getRid().equals(oldRel.getRid())){
                        return false;
                    }
                }
                return true;
            }).collect(Collectors.toList());
            //删除需要删除的关系
            if(!need2DelRel.isEmpty()) {
                metaRelRepository.deleteInBatch(need2DelRel);
            }
            //剩下的也是直接保存
            if(!newRelations.isEmpty()) {
                List<MetaRel> rels = newRelations.stream().map(i -> {
                    MetaRel metaRel = new MetaRel();
                    BeanUtils.copyProperties(i,metaRel);
                    return metaRel;
                }).collect(Collectors.toList());
                metaRelRepository.saveAll(rels);
            }

            //最后保存这个PDM
            MetaCore mc = newOrUpdate(pdm);
            commonSave(mc);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean saveDataSource(MetaDataSource mds) {
        MetaCore mc = newOrUpdate(mds);
        mc.setType(mds.getType());
        return commonSave(mc);
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean addPDMByReverse(String id, String pid) {
        MetaCore parent = metaCoreRepository.getOne(pid);
        if (!parent.getMetaMdl().equals(MetaCoreConstant.CORE_BASEPACKAGE)) {
            throw new RuntimeException("parent node must be a core.BasePackage.");
        }
        DetailVo detailVo = iMetaCoreQueryService.getNodeDetail(id);
        if (!(detailVo instanceof PDMDetailVo)) {
            throw new RuntimeException("this is not pdm's id");
        }
        PDMDetailVo pdmDetailVo = (PDMDetailVo) detailVo;
        return addPDMByReverse(pdmDetailVo, pid);
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean addPDMByReverse(PDMDetailVo vo, String pid) {
        PDM pdm = (PDM) vo.getRealNode();
        List<PDMColumn> columns = vo.getColumns();

        MetaCore pdmMc = new MetaCore();
        pdmMc = dataNodeTransferService.reTransfer(pdmMc, pdm);
        pdmMc.setMetaMdl(MetaCoreConstant.MODEL_PHYSICAL_MODEL);
        pdmMc.setPrtId(pid);
        try{
            pdmMc = metaCoreRepository.save(pdmMc);
            final MetaCore fpdmMc = pdmMc;

            List<MetaCore> columnMcs = columns.stream().map(i -> {
                MetaCore columnMc = new MetaCore();
                columnMc = dataNodeTransferService.reTransfer(columnMc,i);
                columnMc.setPrtId(fpdmMc.getId());
                columnMc.setMetaMdl(MetaCoreConstant.MODEK_PHYSICAL_MODEL_CLM);
                return columnMc;
            }).collect(Collectors.toList());
            metaCoreRepository.saveAll(columnMcs);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean addPDMByReverses(List<String> ids, String pid) {
        try {
            for (String id : ids) {
                boolean res = addPDMByReverse(id,pid);
                if(!res) {
                    return false;
                }
            }
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean deleteMeta(String id) {
        if(id.contains(".")){
            //不是数据库中的元数据的
            return false;
        }
        //需要循环删除子节点
        return deleteMetaRec(id);
    }

    private boolean deleteMetaRec(String pid) {
        List<MetaCore> metaCores = metaCoreRepository.queryByPrtId(pid);
        for (MetaCore metaCore : metaCores) {
            boolean res = deleteMetaRec(metaCore.getId());
            if(!res) {
                return false;
            }
        }
        try{
            metaCoreRepository.deleteById(pid);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean deleteMeta(List<String> ids) {
        for (String id : ids) {
            boolean res = deleteMeta(id);
            if(!res) {
                return false;
            }
        }
        return true;
    }
}
