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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
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.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.persagy.dmp.basic.dto.RequestData;
import com.persagy.dmp.basic.model.CodeTableTypeEnum;
import com.persagy.dmp.codetable.client.CodeTableDataFacade;
import com.persagy.dmp.codetable.entity.CodeTableData;
import com.persagy.dmp.common.constant.CommonConstant;
import com.persagy.dmp.common.constant.ResponseCode;
import com.persagy.dmp.common.constant.ValidEnum;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.dmp.common.model.entity.BaseEntity;
import com.persagy.dmp.common.model.response.CommonResult;
import com.persagy.dmp.common.utils.ResultHelper;
import com.persagy.dmp.define.entity.ObjectInfoDefine;
import com.persagy.dmp.digital.entity.ObjectDigital;
import com.persagy.dmp.rwd.basic.constant.DigitalMessageConstant;
import com.persagy.dmp.rwd.basic.constant.DigitalObjectType;
import com.persagy.dmp.rwd.basic.constant.DigitalRelCode;
import com.persagy.dmp.rwd.basic.utils.DigitalCommonUtils;
import com.persagy.dmp.rwd.basic.utils.DigitalMessageHelper;
import com.persagy.dmp.rwd.define.service.IObjectInfoService;
import com.persagy.dmp.rwd.define.service.IObjectTypeService;
import com.persagy.dmp.rwd.digital.dao.ObjectDigitalMapper;
import com.persagy.dmp.rwd.digital.dao.ObjectRelationMapper;
import com.persagy.dmp.rwd.digital.service.IObjectDigitalService;
import com.persagy.dmp.rwd.parser.service.InfoDataFactory;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 对象数据 实现类
 * @author Charlie Yu
 * @date 2021-07-08
 */
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class ObjectDigitalServiceImpl extends ServiceImpl<ObjectDigitalMapper, ObjectDigital> implements IObjectDigitalService {

    private final ObjectDigitalMapper objectDigitalMapper;
    private final DigitalMessageHelper messageSender;
    private final IObjectInfoService infoService;
    private final IObjectTypeService typeService;
    private final ObjectRelationMapper objectRelationMapper;

    @Override
    public ObjectDigital load(String id) {
        return objectDigitalMapper.selectById(id);
    }

    @Override
    public List<ObjectDigital> queryByCondition(Wrapper<ObjectDigital> queryWrapper) {
        return objectDigitalMapper.selectList(queryWrapper);
    }

    @Override
    public Integer queryCount(Wrapper<ObjectDigital> queryWrapper) {
        return objectDigitalMapper.selectCount(queryWrapper);
    }

    @Override
    public Page queryByCondition(Page page, Wrapper<ObjectDigital> queryWrapper) {
        return objectDigitalMapper.selectPage(page, queryWrapper);
    }

    @Override
    public List<ObjectDigital> insert(List<ObjectDigital> voList) {
        if(CollUtil.isEmpty(voList)) {
            return null;
        }
        validateOnSave(voList, false);
        //获取对象类型
        Map<String, String> typeMap = typeService.queryObjTypeMap();
        voList.forEach(vo -> {
            // 生成ID
            if (StrUtil.isBlank(vo.getId())){
                if (StrUtil.isNotBlank(vo.getObjType())){
                    vo.setId(DigitalCommonUtils.fetchObjectId(vo.getProjectId(), vo.getObjType()));
                }else {
                    vo.setId(DigitalCommonUtils.fetchObjectId(vo.getProjectId(), typeMap.get(vo.getClassCode())));
                }
            }
            //设置对象类型-objType
            vo.setObjType(typeMap.get(vo.getClassCode()));
            vo.setValid(ValidEnum.TRUE.getType());
            // 新增
            objectDigitalMapper.insert(vo);
            // 新增后消息
            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_INSERT, null, vo, false);
        });
        return voList;
    }


    @Override
    public List<ObjectDigital> update(List<ObjectDigital> voList){
        if(CollUtil.isEmpty(voList)) {
            return null;
        }
        //获取$remove字段
        Map<String, Object> removeMap = getRemoveInfo(voList);
        //获取基础属性
        Set<String> fieldSet = ReflectUtil.getFieldMap(ObjectDigital.class).keySet();
        //查询数据库中存在的数据
        List<String> idList = CollUtil.getFieldValues(voList, BaseEntity.PROP_ID, String.class);
        List<ObjectDigital> dbList = objectDigitalMapper.selectBatchIds(idList);
        Map<String, ObjectDigital> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);

        //填充classCode
        fillClassCodeForUpdate(voList,dbMap);
        //信息点校验
        Map<String, Map<String, ObjectInfoDefine>> allInfoMap = validateOnSave(voList, true);
        List<ObjectDigital> resultList = new ArrayList<>();
        voList.forEach(vo -> {
            ObjectDigital dbVO = MapUtil.get(dbMap, vo.getId(), ObjectDigital.class);
            // 容错处理
            if(dbVO == null) {
                return;
            }

            //数据合并
            ObjectDigital newDbVO = dbVO;
            // 合并通用信息点数据
            if (!vo.getObjType().equals(vo.getClassCode())){
                Map<String, ObjectInfoDefine> commonInfoMap = allInfoMap.getOrDefault(vo.getObjType(), new HashMap<>(16));
                dataMerge(newDbVO,vo,commonInfoMap,fieldSet);
            }
            // 合并对象分类信息点数据
            Map<String, ObjectInfoDefine> infoDefineMap = allInfoMap.getOrDefault(vo.getClassCode(),new HashMap<>(16));
            dataMerge(newDbVO,vo,infoDefineMap,fieldSet);

            //移除需要删除的信息点
            Object remove = removeMap.get(newDbVO.getId());
            remove(newDbVO,remove,fieldSet);

            // 修改
            objectDigitalMapper.updateById(newDbVO);
            resultList.add(newDbVO);
            // 修改后消息
            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_UPDATE, dbVO, newDbVO, false);
        });
        return resultList;
    }

    @Override
    public void delete(List<String> idList) {
        if(CollUtil.isEmpty(idList)) {
            return;
        }
        List<ObjectDigital> dbList = objectDigitalMapper.selectBatchIds(idList);
        Map<String, ObjectDigital> dbMap = CollectionUtil.fieldValueMap(dbList, BaseEntity.PROP_ID);
        idList.forEach(id -> {
            ObjectDigital dbVO = MapUtil.get(dbMap, id, ObjectDigital.class);
            // 容错处理
            if(dbVO == null) {
                return;
            }
            // 删除
            ObjectDigital vo = new ObjectDigital();
            vo.setId(id);
            vo.setValid(ValidEnum.FALSE.getType());
            objectDigitalMapper.updateById(vo);
            // 删除后消息
            dbVO.setValid(ValidEnum.FALSE.getType());
            messageSender.sendMessage(DigitalMessageConstant.OPERATE_AFTER_DELETE, null, dbVO, false);
        });
    }

    /***
     * Description: 根据上级id查询下级关联对象
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/24 16:37
     * Update By lijie 2021/8/24 16:37
     */
    @Override
    public CommonResult<List<ObjectDigital>> queryObjectListSuperiorId(RequestData requestData){
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        // 2.当只有项目id时不查询关系,直接根据项目id筛选所有对象
        if (StrUtil.isBlank(requestData.getBuildingId())
                && StrUtil.isBlank(requestData.getFloorId())
                && StrUtil.isBlank(requestData.getEquipmentId())){
            return queryObjectListByProjectId(requestData);
        }
        // 3.存在建筑id/楼层id/设备id
        // 3.1 获取关系code列表
        fillSubordinateRelCode(requestData);
        // 3.2 调用查询语句查询相关内容
        return analysisQueryResultList(objectDigitalMapper.queryObjectListBySuperiorId(requestData),requestData,false,true);
    }
    /***
     * Description: 查询指定楼层下所有指定空间类型的空间
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 9:54
     * Update By lijie 2021/8/30 9:54
     */
    @Override
    public CommonResult<List<ObjectDigital>> querySpaceListByFloorIdAndRoomFuncType(RequestData requestData) {
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        // 2.使用Fl2Sp关系查询楼层下的空间
        requestData.setRelCode(DigitalRelCode.FL_2_SP.getIndex());
        requestData.setObjType(DigitalObjectType.SPACE.getIndex());
        requestData.setRelId(requestData.getFloorId());
        List<List<ObjectDigital>> dataResult = objectDigitalMapper.queryObjectListByFloorIdAndRoomFuncType(requestData);
        return commonAnalysisPageResult(dataResult);
    }
    /***
     * Description:查询指定空间下所有指定对象类型的设备
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 17:03
     * Update By lijie 2021/8/30 17:03
     */
    @Override
    public CommonResult<List<ObjectDigital>> queryEquipListBySpaceIdAndClassCode(RequestData requestData) {
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        // 2.使用Eq2Sp关系查询楼层下的空间
        requestData.setRelCode(DigitalRelCode.EQ_2_SP.getIndex());
        requestData.setObjType(DigitalObjectType.EQUIPMENT.getIndex());
        requestData.setRelId(requestData.getSpaceId());
        List<List<ObjectDigital>> dataResult = objectDigitalMapper.queryObjectListByRelIdAndClassCode(requestData);
        return commonAnalysisPageResult(dataResult);
    }
    /***
     * Description: 按类型编码查询所有设备
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 9:41
     * Update By lijie 2021/8/30 9:41
     */
    @Override
    public CommonResult<List<ObjectDigital>> queryEquipListByClassCode(RequestData requestData) {
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        // 2.使用Fl2Sp关系查询楼层下的空间
        requestData.setObjType(DigitalObjectType.EQUIPMENT.getIndex());
        List<List<ObjectDigital>> dataResult = objectDigitalMapper.queryEquipListByClassCode(requestData);
        return commonAnalysisPageResult(dataResult);
    }
    /***
     * Description: 按系统查询系统下所有设备
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 9:41
     * Update By lijie 2021/8/30 9:41
     */
    @Override
    public CommonResult<List<ObjectDigital>> queryEquipListBySystemId(RequestData requestData) {
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        // 2.使用Sy2Eq关系查询系统下的设备
        requestData.setRelId(requestData.getSystemId());
        requestData.setObjType(DigitalObjectType.EQUIPMENT.getIndex());
        requestData.setRelCode(DigitalRelCode.SY_2_EQ.getIndex());
        List<List<ObjectDigital>> dataResult = objectDigitalMapper.queryObjectListByRelIdAndClassCode(requestData);
        return commonAnalysisPageResult(dataResult);
    }

    /***
     * Description: 支持按指定空间功能类型查询此空间类型及其下级类型的所有空间列表
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 9:41
     * Update By lijie 2021/8/30 9:41
     */
    @Override
    public CommonResult<List<ObjectDigital>> querySpaceListByRoomFuncType(RequestData requestData) {
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        // 2.根据空间功能类型查询其下级空间功能类型
        List<CodeTableData> codeTableDatas = CodeTableDataFacade
                .queryCodeTableDatasByParentCode(AppContext.getContext().getGroupCode(),
                AppContext.getContext().getProjectId(),
                AppContext.getContext().getAppId(),
                AppContext.getContext().getAccountId(),
                RequestData.builder()
                        .typeCode(CodeTableTypeEnum.SPACE.getIndex())
                        .parentCode(requestData.getRoomFuncType())
                        .build());
        if (CollUtil.isEmpty(codeTableDatas)){
            return ResultHelper.multi(new ArrayList<>(),0L);
        }
        // 3.根据分页参数及空间功能类型code数组查询对象
        Set<String> codes = codeTableDatas.stream()
                .map(CodeTableData::getCode)
                .collect(Collectors.toSet());
        QueryWrapper<ObjectDigital> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ObjectDigital.PROP_VALID,true);
        queryWrapper.eq(StrUtil.toUnderlineCase(CommonConstant.QUERY_GROUPCODE),AppContext.getContext().getGroupCode());
        if (StrUtil.isNotBlank(requestData.getProjectId())){
            queryWrapper.eq(StrUtil.toUnderlineCase(CommonConstant.QUERY_PROJECTID),requestData.getProjectId());
        }
        queryWrapper.in("JSON_UNQUOTE(JSON_EXTRACT(infos,'$.roomFuncType'))",codes);
        Page<ObjectDigital> page = new Page<>(requestData.getPage(), requestData.getSize(), true);
        Page<ObjectDigital> digitalPage = objectDigitalMapper.selectPage(page, queryWrapper);
        return ResultHelper.multi(digitalPage.getRecords(),digitalPage.getTotal());
    }

    /***
     * Description: 根据图类型编码及关系类型编码查询对象及其关联对象
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 9:41
     * Update By lijie 2021/8/30 9:41
     */
    @Override
    public CommonResult<List<ObjectDigital>> queryObjectListByGraphCodeAndRelCode(RequestData requestData) {
        // 1.计算分页参数
        DigitalCommonUtils.computePageParam(requestData);
        List<List<ObjectDigital>> objList = objectDigitalMapper.queryObjectListByGraphCodeAndRelCode(requestData);
        return analysisQueryResultList(objList,requestData,false,false);
    }
    /***
     * Description: 根据对象id批量更新对象的classCode
     * @param objectDigitals : 对象数组
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/9/27 17:46
     * Update By lijie 2021/9/27 17:46
     */
    @Override
    public CommonResult<List<ObjectDigital>> batchUpdateClassCodesByIds(List<ObjectDigital> objectDigitals) {
        // 1.校验数据必填
        for (ObjectDigital objectDigital : objectDigitals) {
            if (StrUtil.isBlank(objectDigital.getId())
                    || StrUtil.isBlank(objectDigital.getClassCode())){
                throw new BusinessException(ResponseCode.A0400.getCode(),
                        StrUtil.format("id:{}或classCode:{}不能为空",objectDigital.getId(),
                                objectDigital.getClassCode()));
            }
        }
        // 2.校验对象是否都存在以及对象要更新的classCode是否符合
        // 2.1 获得对象id集合
        Set<String> objIds = objectDigitals.stream()
                .map(BaseEntity::getId)
                .collect(Collectors.toSet());
        Map<String, ObjectDigital> digitalMap = objectDigitals
                .stream()
                .collect(Collectors.toMap(ObjectDigital::getId, obj -> obj, (k1, k2) -> k1));
        // 2.2 根据对象id查询对象信息及对象的分类对应的classCode集合
        List<ObjectDigital> queryObjs = objectDigitalMapper.queryObjectListByIds(objIds);
        if (CollUtil.isEmpty(queryObjs)){
            throw new BusinessException(ResponseCode.A0400.getCode(),
                    StrUtil.format("id不存在:{}",objIds));
        }
        // 2.3 校验对象是否都存在
        Map<String, ObjectDigital> queryObjMap = queryObjs
                .stream()
                .collect(Collectors.toMap(BaseEntity::getId, obj -> obj, (k1, k2) -> k1));
        List<ObjectDigital> updateObjs = new ArrayList<>();
        for (String objId : objIds) {
            if (!queryObjMap.containsKey(objId)){
                throw new BusinessException(ResponseCode.A0400.getCode(),
                        StrUtil.format("id不存在:{}",objId));
            }
            ObjectDigital queryObj = queryObjMap.get(objId);
            Set<String> validClassCodes = CollUtil.defaultIfEmpty(queryObj.getObjTypeClassCodes(), new HashSet<>());
            ObjectDigital objectDigital = digitalMap.get(objId);
            if (!validClassCodes.contains(objectDigital.getClassCode())){
                throw new BusinessException(ResponseCode.A0400.getCode(),
                        StrUtil.format("id:{}的classCode不符合:{}",objectDigital.getId(),objectDigital.getClassCode()));
            }
            queryObj.setClassCode(objectDigital.getClassCode());
            queryObj.setUpdateApp(AppContext.getContext().getAppId());
            queryObj.setModifier(AppContext.getContext().getAccountId());
            updateObjs.add(queryObj);
        }
        // 3.校验通过,直接更新
        updateBatchById(updateObjs);
        return ResultHelper.multi(new ArrayList<>());
    }

    /***
     * Description: 通用处理分页数据方法
     * @param dataResult : 分页数据
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/30 14:15
     * Update By lijie 2021/8/30 14:15
     */
    private CommonResult<List<ObjectDigital>> commonAnalysisPageResult(List<List<ObjectDigital>> dataResult) {
        if (CollUtil.isEmpty(dataResult) || dataResult.size()<2){
            return ResultHelper.multi(new ArrayList<>(),0L);
        }
        List<ObjectDigital> objectDigitals = dataResult.get(0);
        if (CollUtil.isEmpty(objectDigitals)){
            return ResultHelper.multi(new ArrayList<>(),0L);
        }
        ObjectDigital pageParam = dataResult.get(1).get(0);
        return ResultHelper.multi(objectDigitals,pageParam.getTotalCount());
    }

//    /***
//     * Description: 计算分页参数
//     * @param requestData : 请求参数
//     * @return : void
//     * @author : lijie
//     * @date :2021/8/30 10:01
//     * Update By lijie 2021/8/30 10:01
//     */
//    private void computePageParam(RequestData requestData) {
//        if (null==requestData.getPage()){
//            requestData.setPage(1L);
//        }
//        // 默认分页条数,防止大量查询
//        long defaultSize = SpringHelper.getLong(CommonConstant.QUERY_PAGE_SIZE_KEY, CommonConstant.QUERY_DEFAULT_PAGE_SIZE);
//        if (null==requestData.getSize() || requestData.getSize()>defaultSize){
//            requestData.setSize(defaultSize);
//        }
//        requestData.setSkip((requestData.getPage()-1)*requestData.getSize());
//    }

    /***
     * Description: 根据对象id获取下级关系code数组
     * @param requestData : 请求参数
     * @return : void
     * @author : lijie
     * @date :2021/8/24 21:20
     * Update By lijie 2021/8/24 21:20
     */
    private void fillSubordinateRelCode(RequestData requestData) {
        if (StrUtil.isNotBlank(requestData.getEquipmentId())){
            // 设备下的部件
            requestData.setRelCodes(CollUtil.newHashSet(DigitalRelCode.EQ_2_EC.getIndex()));
            requestData.setFilterObjId(requestData.getEquipmentId());
            return;
        }
        if (StrUtil.isNotBlank(requestData.getFloorId())){
            // 楼层下的空间,设备,系统
            requestData.setRelCodes(CollUtil.newHashSet(DigitalRelCode.FL_2_SP.getIndex(),
                    DigitalRelCode.EQ_2_FL.getIndex(),DigitalRelCode.SY_2_FL.getIndex()));
            // 设置设备查询部件
            requestData.setQueryEcFlag(true);
            requestData.setEcRelCodes(CollUtil.newHashSet(DigitalRelCode.EQ_2_EC.getIndex()));
            requestData.setFilterObjId(requestData.getFloorId());
            return;
        }
        if (StrUtil.isNotBlank(requestData.getBuildingId())){
            // 建筑下的楼层,空间,设备,系统
            requestData.setRelCodes(CollUtil.newHashSet(DigitalRelCode.BD_2_FL.getIndex(),
                    DigitalRelCode.BD_2_SP.getIndex(),DigitalRelCode.SY_2_BD.getIndex(),
                    DigitalRelCode.EQ_2_BD.getIndex(),DigitalRelCode.BD_2_SH.getIndex()));
            // 设置设备查询部件
            requestData.setQueryEcFlag(true);
            requestData.setEcRelCodes(CollUtil.newHashSet(DigitalRelCode.EQ_2_EC.getIndex()));
            requestData.setFilterObjId(requestData.getBuildingId());
        }
    }

    /***
     * Description: 根据项目id查询对象列表
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/24 16:40
     * Update By lijie 2021/8/24 16:40
     */
    private CommonResult<List<ObjectDigital>> queryObjectListByProjectId(RequestData requestData) {
        // 1.查询结果集
        List<List<ObjectDigital>> resultList =
                objectDigitalMapper.queryObjectDigitalsByProjectId(requestData,requestData.getSkip(),requestData.getSize());
        return analysisQueryResultList(resultList,requestData,true,true);
    }
    /***
     * Description: 解析结果集
     * @param resultList : 结果集
     * @param requestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.digital.entity.ObjectDigital>>
     * @author : lijie
     * @date :2021/8/25 13:16
     * Update By lijie 2021/8/25 13:16
     */
    private CommonResult<List<ObjectDigital>> analysisQueryResultList(List<List<ObjectDigital>> resultList,
                                                                      RequestData requestData,
                                                                      Boolean fillRelFlag,
                                                                      Boolean fillSpaceFlag) {
        if (CollUtil.isEmpty(resultList)){
            return ResultHelper.multi(new ArrayList<>(),0);
        }
        List<ObjectDigital> pageResult = resultList.get(0);
        List<ObjectDigital> totalCount = resultList.get(1);
        if (CollUtil.isEmpty(pageResult)){
            return ResultHelper.multi(new ArrayList<>(),0);
        }
        if (requestData.isOnlyCount()){
            // 只返回数
            return ResultHelper.multi(new ArrayList<>(),totalCount.get(0).getTotalCount());
        }
        fillRelIds(pageResult,fillRelFlag);
        // 2.过滤信息点
        retainObjInfos(pageResult,requestData.getReturnInfos());
        // 3.处理Fl2Sp的关系,将对应的空间对象的楼层id扔进去
        fillFloorIdIntoSpaceObjFromIds(pageResult,fillSpaceFlag);
        return ResultHelper.multi(pageResult,totalCount.get(0).getTotalCount());
    }

    /***
     * Description: 当只有项目时需要填充关系id
     * @param pageResult : 查询的结果集
     * @param fillRelFlag : 0-不注入关系数据,1-注入关系数据
     * @return : void
     * @author : lijie
     * @date :2021/9/4 22:39
     * Update By lijie 2021/9/4 22:39
     */
    private void fillRelIds(List<ObjectDigital> pageResult,
                            Boolean fillRelFlag) {
        if (null==fillRelFlag || !fillRelFlag){
            return;
        }
        // 注入关系
        // 2.1 根据楼层id查询建筑id
        // 2.2 根据空间id查询建筑id
        // 2.3 根据设备id查询建筑id
        // 2.4 根据系统id查询建筑id
        // 2.5 根据竖井id查询建筑id
        Set<String> objIds = pageResult.stream()
                .filter(object->!DigitalObjectType.BUILDING.getIndex().equals(object.getObjType()))
                .map(ObjectDigital::getId)
                .collect(Collectors.toSet());
        if (CollUtil.isEmpty(objIds)){
            return;
        }
        List<ObjectDigital> objectDigitals = objectRelationMapper.selectRelCodesByObjIdsAndRelCodes(objIds, CollUtil
                .newHashSet(DigitalRelCode.EQ_2_EC.getIndex(), DigitalRelCode.BD_2_FL.getIndex(),
                        DigitalRelCode.BD_2_SP.getIndex(), DigitalRelCode.SY_2_BD.getIndex(),
                        DigitalRelCode.EQ_2_BD.getIndex(),DigitalRelCode.BD_2_SH.getIndex()));
        if (CollUtil.isEmpty(objectDigitals)){
            return;
        }
        Map<String, ObjectDigital> digitalMap = objectDigitals.stream()
                .collect(Collectors.toMap(ObjectDigital::getId, objectDigital -> objectDigital, (k1, k2) -> k1));
        for (ObjectDigital objectDigital : pageResult) {
            if (!digitalMap.containsKey(objectDigital.getId())){
                continue;
            }
            objectDigital.setObjToIds(CollUtil
                    .defaultIfEmpty(digitalMap.get(objectDigital.getId()).getObjToIds(),new HashSet<>()));
            objectDigital.setObjFromIds(CollUtil
                    .defaultIfEmpty(digitalMap.get(objectDigital.getId()).getObjFromIds(),new HashSet<>()));
        }
    }

    /***
     * Description: 填充关系id
     * @param objectDigitals : 查询结果集
     * @return : void
     * @author : lijie
     * @date :2021/8/26 12:00
     * Update By lijie 2021/8/26 12:00
     */
    private void fillFloorIdIntoSpaceObjFromIds(List<ObjectDigital> objectDigitals,Boolean fillSpaceFlag) {
        if (null==fillSpaceFlag || !fillSpaceFlag){
            return;
        }
        // 1.获得空间id
        Set<String> spaceIds = objectDigitals.stream()
                .filter(objectDigital -> DigitalObjectType.SPACE.getIndex().equals(objectDigital.getObjType()))
                .map(ObjectDigital::getId)
                .collect(Collectors.toSet());
        if (CollUtil.isEmpty(spaceIds)){
            return;
        }
        List<ObjectDigital> relResult = objectRelationMapper.selectRelCodesByObjToIdsAndRelCode(spaceIds,DigitalRelCode.FL_2_SP.getIndex());
        if (CollUtil.isEmpty(relResult)){
            return;
        }
        Map<String, Set<String>> setMap = relResult
                .stream()
                .collect(Collectors.toMap(ObjectDigital::getId, ObjectDigital::getObjFromIds, (k1, k2) -> k1));
        for (ObjectDigital objectDigital : objectDigitals) {
            Set<String> objFromIds = CollUtil.defaultIfEmpty(objectDigital.getObjFromIds(),new HashSet<>());
            objFromIds.addAll(setMap.getOrDefault(objectDigital.getId(),new HashSet<>()));
            objectDigital.setObjFromIds(objFromIds);
        }
    }

    /***
     * Description: 过滤掉不需要的信息点
     * @param objectDigitals : 查询结果集
     * @param returnInfos : 返回的信息点key
     * @return : void
     * @author : lijie
     * @date :2021/8/25 13:13
     * Update By lijie 2021/8/25 13:13
     */
    private void retainObjInfos(List<ObjectDigital> objectDigitals, Set<String> returnInfos) {
        if (CollUtil.isEmpty(returnInfos) || CollUtil.isEmpty(objectDigitals)){
            return;
        }
        for (ObjectDigital objectDigital : objectDigitals) {
            ObjectNode infos = objectDigital.getInfos();
            if (null==infos || infos.size()<=0){
                continue;
            }
            infos.retain(returnInfos);
        }
    }

    /**
     * 保存校验
     * 编码全局唯一
     * @param voList
     * @param isUpdate
     */
    private Map<String, Map<String, ObjectInfoDefine>> validateOnSave(List<ObjectDigital> voList, boolean isUpdate) {
        return validateInfoCode(voList);
    }

    /**
     * 信息点值校验
     * @param voList
     */
    private Map<String, Map<String, ObjectInfoDefine>> validateInfoCode(List<ObjectDigital> voList) {
        //获取该信息点当前classCode
        List<String> typeCodeList = CollUtil.getFieldValues(voList, "classCode", String.class);

        //查询通用类型：equipment,building,floor,space等
        Map<String, String> objTypeMap = typeService.queryObjTypeMap();
        queryParentClassCode(typeCodeList,objTypeMap);

        // 查询信息点定义
        Map<String, Map<String, ObjectInfoDefine>> allInfoMap = infoService.queryByTypes(typeCodeList);
        // 信息点校验器
        for(ObjectDigital vo:voList) {
            //设置自定义信息点
            Map<String, ObjectInfoDefine> infoMap = new HashMap<>(16);
            if(CollUtil.isNotEmpty(allInfoMap)){
                Map<String, ObjectInfoDefine> infoDefineMap = allInfoMap.get(vo.getClassCode());
                if(CollUtil.isNotEmpty(infoDefineMap)){
                    infoMap.putAll(infoDefineMap);
                }
            }
            String objType = objTypeMap.getOrDefault(vo.getClassCode(),"");
            //设置通用信息点
            if(!objType.equals(vo.getClassCode()) && MapUtil.isNotEmpty(allInfoMap)){
                Map<String, ObjectInfoDefine> commonInfoDefineMap = allInfoMap.getOrDefault(objType,new HashMap<>(16));
                if(null!=commonInfoDefineMap && commonInfoDefineMap.size()>0){
                    infoMap.putAll(commonInfoDefineMap);
                }
            }
            if(MapUtil.isEmpty(infoMap)) {
                continue;
            }
            // 信息点值对象
            ObjectNode infos = vo.getInfos();
            if(infos == null || infos.isNull()) {
                continue;
            }
            // 按infos属性循环处理
            Iterator<String> infoKeys = infos.fieldNames();
            while(infoKeys.hasNext()) {
                String infoCode = infoKeys.next();
                // 如果信息点中不存在，移除
                if(!infoMap.containsKey(infoCode)) {
                    // infos.remove(infoCode);
                    infoKeys.remove();
                    continue;
                }
                // 校验信息点值
                InfoDataFactory.parse(infoMap.get(infoCode), infos.get(infoCode));

            }
        }
        return allInfoMap;
    }

    /**
     * 获取remove信息点
     * @param voList
     * @return
     */
    private Map<String, Object> getRemoveInfo(List<ObjectDigital> voList){
        Map<String, Object> removeMap = new HashMap<>(16);
        for (ObjectDigital digital : voList) {
            ObjectNode infos = digital.getInfos();
            if(infos!=null){
                removeMap.put(digital.getId(),infos.get("$remove"));
            }
        }
        return removeMap;
    }

    /**
     * 查询对应的通用类型
     * @param typeCodeList
     */
    private void  queryParentClassCode(List<String> typeCodeList,Map<String, String> objTypeMap){
        if(typeCodeList == null || typeCodeList.size()<=0){
            return;
        }
        //查询classCode对应点objType
        List<String> parentCodes = new ArrayList<>();
        for (String classCode : typeCodeList) {
            String objType = objTypeMap.get(classCode);
            if(StringUtils.isEmpty(objType) || "0".equals(objType) || parentCodes.contains(objType)){
                return ;
            }
            parentCodes.add(objType);
        }
        typeCodeList.addAll(parentCodes);
    }
    /**
     * 数据合并
     * @param dbVO 源数据
     * @param vo 目标数据
     * @param vo 待删除待数据
     */
    private void dataMerge(ObjectDigital dbVO,ObjectDigital vo,Map<String, ObjectInfoDefine> infoDefineMap,Set<String> fieldSet){
        //基础属性处理
        handleBasicColumn(dbVO,vo);
        //动态信息点处理
        ObjectNode infos = vo.getInfos();
        for (Map.Entry<String, ObjectInfoDefine> entry : infoDefineMap.entrySet()) {
            String code = entry.getKey();
            if(fieldSet.contains(code)){
                //属于基础信息点
                continue;
            }
            if (!infos.has(code)) {
                continue;
            }
            JsonNode value = infos.get(code);
            if (dbVO.getInfos() == null) {
                dbVO.setInfos(JsonNodeFactory.instance.objectNode());
            }
            dbVO.getInfos().set(code, value);
        }
    }

    /**
     * 基础属性处理
     * @param dbVO
     * @param vo
     */
    private void handleBasicColumn(ObjectDigital dbVO,ObjectDigital vo){
        if(StringUtils.isNotEmpty(vo.getName())){
            dbVO.setName(vo.getName());
        }
        if(StringUtils.isNotEmpty(vo.getLocalId())){
            dbVO.setLocalId(vo.getLocalId());
        }
        if(StringUtils.isNotEmpty(vo.getLocalName())){
            dbVO.setLocalName(vo.getLocalName());
        }
        if(vo.getVirtualCodes()!=null){
            dbVO.setVirtualCodes(vo.getVirtualCodes());
        }
        if(vo.getValid()!=null){
            dbVO.setValid(vo.getValid());
        }
    }


    /**
     * 删除需要移除的信息点
     * @param dbVO
     * @param remove
     * @param basicFieldSet
     */
    private void remove(ObjectDigital dbVO,Object remove,Set<String> basicFieldSet){
        if(remove == null){
            return;
        }
        JSONArray array = JSONArray.parseArray(remove.toString());
        array.forEach(item->{
            String removeCode = (String) item;
            if(basicFieldSet.contains(removeCode)){
                //基础信息
                if("name".equals(removeCode)){
                    dbVO.setName(null);
                }
                if("localId".equals(removeCode)){
                    dbVO.setLocalId(null);
                }
                if("localName".equals(removeCode)){
                    dbVO.setLocalName(null);
                }
                if("virtualCodes".equals(removeCode)){
                    dbVO.setVirtualCodes(new ArrayList<>());
                }
                return;
            }
            dbVO.getInfos().remove(removeCode);
        });
    }

    /**
     * 修改时填充classCode
     * @param voList
     * @param dbMap
     */
    private void fillClassCodeForUpdate(List<ObjectDigital> voList,Map<String, ObjectDigital> dbMap){
        if(voList == null || voList.size()<=0){
            return;
        }
        for (ObjectDigital digital : voList) {
            ObjectDigital dbDigital = dbMap.get(digital.getId());
            if(dbDigital!=null && StrUtil.isBlank(digital.getClassCode())){
                digital.setClassCode(dbDigital.getClassCode());
            }
            if(dbDigital!=null && StrUtil.isBlank(digital.getObjType())){
                digital.setObjType(dbDigital.getObjType());
            }
        }
    }


    /**
     * 查询虚拟信息点
     * @param projectId
     * @param groupCode
     * @param ids
     * @return
     */
    @Override
    public Map<String, List<String>> queryVirtualCodeMap(String projectId,String groupCode,List<String> ids) {
        LambdaQueryWrapper<ObjectDigital> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(ObjectDigital::getId, ObjectDigital::getVirtualCodes);
        wrapper.eq(ObjectDigital::getProjectId,projectId);
        wrapper.eq(ObjectDigital::getGroupCode,groupCode);
        wrapper.in(ObjectDigital::getId,ids);
        wrapper.eq(ObjectDigital::getValid, ValidEnum.TRUE.getType());
        List<ObjectDigital> objectDigitals = queryByCondition(wrapper);
        return CollUtil.fieldValueAsMap(objectDigitals, "id", "virtual_codes");
    }

}
