package com.persagy.dmp.rwd.delivery.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.persagy.dmp.common.constant.ValidEnum;
import com.persagy.dmp.common.model.entity.BaseEntity;
import com.persagy.dmp.define.entity.ObjectTypeDefine;
import com.persagy.dmp.delivery.dto.DeliveryPlanDTO;
import com.persagy.dmp.delivery.dto.ObjectTypeCollectDTO;
import com.persagy.dmp.delivery.entity.BossBdtpTypeRel;
import com.persagy.dmp.delivery.entity.ObjectInfoCollect;
import com.persagy.dmp.delivery.entity.ObjectTypeCollect;
import com.persagy.dmp.delivery.entity.RelationDefineCollect;
import com.persagy.dmp.rwd.define.service.IObjectTypeService;
import com.persagy.dmp.rwd.delivery.dao.ObjectTypeCollectMapper;
import com.persagy.dmp.rwd.delivery.service.IObjectInfoCollectService;
import com.persagy.dmp.rwd.delivery.service.IObjectTypeCollectService;
import com.persagy.dmp.rwd.delivery.service.IRelationDefineCollectService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 项目，现场交付范围管理-对象类型
 * @author:linhuili
 * @date:2021/10/13
 */
@Service
@Slf4j
public class ObjectTypeCollectServiceImpl extends ServiceImpl<ObjectTypeCollectMapper, ObjectTypeCollect> implements IObjectTypeCollectService {

    @Autowired
    private com.persagy.dmp.rwd.delivery.dao.ObjectTypeCollectMapper ObjectTypeCollectMapper;

    @Autowired
    private IObjectTypeService objectTypeService;

    @Autowired
    private IObjectTypeCollectService objectTypeCollectService;

    @Autowired
    private IObjectInfoCollectService objectInfoCollectService;

    @Autowired
    private IRelationDefineCollectService relationDefineCollectService;

    /**
     * 数量统计
     * @param queryWrapper 查询条件
     * @return
     */
    @Override
    public Integer queryCount(Wrapper<ObjectTypeCollect> queryWrapper) {
        return ObjectTypeCollectMapper.selectCount(queryWrapper);
    }

    /**
     * 查询对象类型交付范围
     * @param queryWrapper 查询条件
     * @return
     */
    @Override
    public List<ObjectTypeCollect> queryByCondition(Wrapper<ObjectTypeCollect> queryWrapper) {
        return ObjectTypeCollectMapper.selectList(queryWrapper);
    }

    /**
     * 生成项目交付范围信息
     * @param voList
     * @return
     * @throws Exception
     */
    @Override
    public List<DeliveryPlanDTO> createProjectDelivery(List<DeliveryPlanDTO> voList) throws Exception {
        //1. 查询BDTP标准交付范围-对象类型
        Map<String, ObjectTypeCollect> typeCollectMap = queryBdtpObjectTypeCollect();
        //2. 查询BDTP标准交付范围-信息点
        Map<String, List<ObjectInfoCollect>> infoCollectMap = queryBdtpObjectInfoCollect();
        //3. 查询BDTP标准交付范围- 关系
        List<RelationDefineCollect> relationCollectList = queryBdtpObjectRelCollect();
        //4. 初始化项目交付范围

        //5.1 初始化对象类型交付范围
        initDelivertyObjectType(voList,typeCollectMap);
        //5.2 初始化信息点交付范围
        initDelivertyObjectInfo(voList,infoCollectMap);
        //5.3 初始化关系交付范围
        initDeliveryGraphRel(voList,relationCollectList);
        return new ArrayList<>();
    }

    /**
     * 设定对象类型交付范围
     * @param voList 待新增数据
     * @return
     */
    @Override
    public List<ObjectTypeCollect> insert(List<ObjectTypeCollect> voList) throws Exception{
        //填充信息点采集ID
        fillObjectTypeCollectId(voList);
        //新增采集信息点
        saveOrUpdateBatch(voList);
        return voList;
    }

    /**
     * 修改对象类型交付范围
     * @param voList 待修改数据
     * @return
     */
    @Override
    public List<ObjectTypeCollect> update(List<ObjectTypeCollect> voList) throws Exception {
        //填充信息点采集ID
        fillObjectTypeCollectId(voList);
        //修改采集信息点
        saveOrUpdateBatch(voList);
        return voList;
    }

    /**
     * 删除对象类型交付范围
     * @param idList 主键
     */
    @Override
    public void delete(List<String> idList) {
        if(CollUtil.isEmpty(idList)) {
            return;
        }
        List<ObjectTypeCollect> dbList = ObjectTypeCollectMapper.selectBatchIds(idList);
        Map<String, ObjectTypeCollect> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
        idList.forEach(id -> {
            ObjectTypeCollect dbVO = MapUtil.get(dbMap, id, ObjectTypeCollect.class);
            // 容错处理
            if(dbVO == null) {
                return;
            }
            // 删除
            ObjectTypeCollect vo = new ObjectTypeCollect();
            vo.setId(id);
            vo.setValid(ValidEnum.FALSE.getType());
            ObjectTypeCollectMapper.updateById(vo);
        });
    }


    /**
     * 填充已交付的对象类ID
     * @param voList
     */
    private void fillObjectTypeCollectId(List<ObjectTypeCollect> voList){
        if(CollUtil.isEmpty(voList)){
            return;
        }
        for (ObjectTypeCollect typeCollect : voList) {
            if(StringUtils.isNotEmpty(typeCollect.getId()) || StringUtils.isEmpty(typeCollect.getDefineTypeId())){
                continue;
            }
            //查询采集信息点
            LambdaQueryWrapper<ObjectTypeCollect> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ObjectTypeCollect::getGroupCode,typeCollect.getGroupCode());
            wrapper.eq(ObjectTypeCollect::getProjectId,typeCollect.getProjectId());
            wrapper.eq(ObjectTypeCollect::getDeliveryType,typeCollect.getDeliveryType());
            wrapper.eq(ObjectTypeCollect::getDefineTypeId,typeCollect.getDefineTypeId());
            wrapper.eq(ObjectTypeCollect::getValid,true);
            List<ObjectTypeCollect> ObjectTypeCollects = queryByCondition(wrapper);
            if(CollUtil.isEmpty(ObjectTypeCollects)){
                //信息点未被采集
                continue;
            }else{
                //信息点已采集
                typeCollect.setId(ObjectTypeCollects.get(0).getId());
            }
        }
    }

    /**
     * 分页查询对象类型交付范围
     * @param page 分页条件
     * @param queryWrapper 查询条件
     * @return
     */
    @Override
    public Page queryByCondition(Page page, Wrapper<ObjectTypeCollect> queryWrapper) {
        //查询交付范围内的对象类型信息
        Page selectPage = ObjectTypeCollectMapper.selectPage(page, queryWrapper);
        List<ObjectTypeCollect> records = (List<ObjectTypeCollect>)selectPage.getRecords();
        if(CollUtil.isEmpty(records)){
            return selectPage;
        }
        Map<String, ObjectTypeDefine> typeDefineMap = queryDefineObjectType(records);

        List<ObjectTypeCollectDTO> result = new ArrayList<>();
        records.forEach(item->{
            ObjectTypeCollectDTO collectType = new ObjectTypeCollectDTO();
            //设置标准类型定义信息
            String defineTypeId = item.getDefineTypeId();
            if(StringUtils.isNotEmpty(defineTypeId)){
                ObjectTypeDefine objectTypeDefine = typeDefineMap.get(defineTypeId);
                if(objectTypeDefine != null){
                    BeanUtils.copyProperties(objectTypeDefine,collectType);
                }
            }
            BeanUtils.copyProperties(item,collectType);
            result.add(collectType);
        });
        selectPage.setRecords(result);
        return selectPage;
    }

    /**
     * 查询标准类型定义
     * @return
     */
    private Map<String, ObjectTypeDefine> queryDefineObjectType(List<ObjectTypeCollect> records){
        Set<String> ids = records.stream().map(ObjectTypeCollect::getDefineTypeId).collect(Collectors.toSet());
        QueryWrapper<ObjectTypeDefine> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id",ids);
        //queryWrapper.select("id","name");
        List<ObjectTypeDefine> objectTypeDefines = objectTypeService.queryByCondition(queryWrapper);
        if(CollUtil.isEmpty(objectTypeDefines)){
            return new HashMap<>();
        }
        return objectTypeDefines.stream().collect(Collectors.toMap(ObjectTypeDefine::getId, item->item, (k1, k2) -> k1));
    }

    /**
     * 查询BDTP标准交付范围-对象类型
     */
    private Map<String,ObjectTypeCollect> queryBdtpObjectTypeCollect(){
        LambdaQueryWrapper<ObjectTypeCollect> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ObjectTypeCollect::getGroupCode,"0");
        wrapper.eq(ObjectTypeCollect::getProjectId,"0");
        wrapper.eq(ObjectTypeCollect::getIsDelivery,1);
        wrapper.eq(ObjectTypeCollect::getValid,ValidEnum.TRUE.getType());
        List<ObjectTypeCollect> objectTypeCollects = objectTypeCollectService.queryByCondition(wrapper);
        if(CollUtil.isEmpty(objectTypeCollects)){
            return new HashMap<>();
        }
        return objectTypeCollects.stream().collect(Collectors.toMap(ObjectTypeCollect::getCode, item->item, (k1, k2) -> k1));
    }

    /**
     * 查询BDTP标准交付范围-信息点
     */
    private Map<String, List<ObjectInfoCollect>> queryBdtpObjectInfoCollect(){
        LambdaQueryWrapper<ObjectInfoCollect> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ObjectInfoCollect::getGroupCode,"0");
        wrapper.eq(ObjectInfoCollect::getProjectId,"0");
        wrapper.eq(ObjectInfoCollect::getIsDelivery,1);
        wrapper.eq(ObjectInfoCollect::getValid,ValidEnum.TRUE.getType());
        List<ObjectInfoCollect> objectInfoCollects = objectInfoCollectService.queryByCondition(wrapper);
        if(CollUtil.isEmpty(objectInfoCollects)){
            return new HashMap<>();
        }
        return objectInfoCollects.stream().collect(Collectors.groupingBy(ObjectInfoCollect::getClassCode));
    }

    /**
     * 查询BDTP标准交付范围-关系
     */
    private List<RelationDefineCollect> queryBdtpObjectRelCollect(){
        LambdaQueryWrapper<RelationDefineCollect> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RelationDefineCollect::getGroupCode,"0");
        wrapper.eq(RelationDefineCollect::getProjectId,"0");
        wrapper.eq(RelationDefineCollect::getValid,ValidEnum.TRUE.getType());
        return relationDefineCollectService.queryByCondition(wrapper);
    }

    /**
     * 初始化对象类型交付范围
     * @param deliverPlanList
     */
    private void initDelivertyObjectType(List<DeliveryPlanDTO> deliverPlanList,Map<String, ObjectTypeCollect> typeCollectMap) throws Exception{
        if(CollUtil.isEmpty(deliverPlanList) || CollUtil.isEmpty(typeCollectMap)){
            return;
        }
        //组装类型交付信息
        List<ObjectTypeCollect> content = new ArrayList<>();
        for (DeliveryPlanDTO deliveryPlan : deliverPlanList) {
            String classCode = deliveryPlan.getClassCode();
            ObjectTypeCollect typeCollect = typeCollectMap.get(classCode);
            if(typeCollect == null){
                log.info("BOSS项目范围交付：交付类型不在BDTP标准交付范围内：{}"+classCode);
                continue;
            }
            typeCollect.setGroupCode(deliveryPlan.getGroupCode());
            typeCollect.setProjectId(deliveryPlan.getProjectId());
            typeCollect.setIsDelivery(1);
            content.add(typeCollect);
        }
        if(CollUtil.isEmpty(content)){
            log.info("BOSS项目范围交付：无类型交付信息");
            return;
        }
        //类型信息交付
        objectTypeCollectService.insert(content);
    }


    /**
     * 初始化对象类型交付范围
     * @param deliverPlanList
     */
    private void initDelivertyObjectInfo(List<DeliveryPlanDTO> deliverPlanList,Map<String, List<ObjectInfoCollect>> infoCollectMap) throws Exception{
        if(CollUtil.isEmpty(deliverPlanList) || CollUtil.isEmpty(infoCollectMap)){
            return;
        }
        //组装信息点交付信息
        List<ObjectInfoCollect> content = new ArrayList<>();
        for (DeliveryPlanDTO deliveryPlan : deliverPlanList) {
            String classCode = deliveryPlan.getClassCode();
            List<ObjectInfoCollect> infoCollectList = infoCollectMap.get(classCode);
            if(CollUtil.isEmpty(infoCollectList)){
                log.info("该类型下无需交付的信息点：{}"+classCode);
                continue;
            }
            infoCollectList.forEach(item->{
                item.setGroupCode(deliveryPlan.getGroupCode());
                item.setProjectId(deliveryPlan.getProjectId());
                item.setIsDelivery(true);
                content.add(item);
            });
        }
        if(CollUtil.isEmpty(content)){
            log.info("BOSS项目范围交付：无信息点交付信息");
            return;
        }
        //类型信息交付
        objectInfoCollectService.insert(content);
    }

    /**
     * 初始化交付范围关系定义
     * @param deliverPlanList
     * @param relDefineCollectList
     */
    private void initDeliveryGraphRel(List<DeliveryPlanDTO> deliverPlanList,List<RelationDefineCollect> relDefineCollectList) throws Exception {
        if(CollUtil.isEmpty(deliverPlanList) || CollUtil.isEmpty(relDefineCollectList)){
            return;
        }
        Set<String> allTypeCodes = relDefineCollectList.stream().map(RelationDefineCollect::getId).collect(Collectors.toSet());
        List<RelationDefineCollect> result = new ArrayList<>();
        for (RelationDefineCollect relCollect : relDefineCollectList) {
            ArrayNode sourceTypeCodes = relCollect.getSourceTypeCodes();
            //获取源端和末端对象类型在交付范围内的对象类型
            if(CollUtil.isNotEmpty(sourceTypeCodes)){
                sourceTypeCodes = getInDeliveryTypeCode(sourceTypeCodes, allTypeCodes);
            }
            ArrayNode endTypeCodes = relCollect.getEndTypeCodes();
            if(CollUtil.isNotEmpty(endTypeCodes)){
                endTypeCodes = getInDeliveryTypeCode(endTypeCodes, allTypeCodes);
            }
            if(CollUtil.isEmpty(sourceTypeCodes) && CollUtil.isEmpty(endTypeCodes)){
                continue;
            }
            //重置源端和末端对象类型
            relCollect.setSourceTypeCodes(sourceTypeCodes);
            relCollect.setEndTypeCodes(endTypeCodes);
            //设置项目信息
            relCollect.setGroupCode(relDefineCollectList.get(0).getGroupCode());
            relCollect.setProjectId(relDefineCollectList.get(0).getProjectId());
            result.add(relCollect);
        }
        //2.初始化关系交付范围
        relationDefineCollectService.insert(result);
    }

    /**
     * 获取类型在交付范围内的关系数据
     * @param typeCodes
     * @param allTypeCodes
     * @return
     */
    private ArrayNode getInDeliveryTypeCode(ArrayNode typeCodes,Set<String> allTypeCodes){
        ArrayNode array = JsonNodeFactory.instance.arrayNode();
        if(CollUtil.isEmpty(typeCodes) || CollUtil.isEmpty(allTypeCodes)){
            return array;
        }
        typeCodes.forEach(item->{
            if(allTypeCodes.contains(item)){
                array.add(item);
            }
        });
        return array;
    }
}
