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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.persagy.dmp.basic.dto.DefineRequestData;
import com.persagy.dmp.basic.model.QueryCriteria;
import com.persagy.dmp.basic.utils.QueryCriteriaHelper;
import com.persagy.dmp.common.constant.ResponseCode;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.lang.PsDateTime;
import com.persagy.dmp.common.model.response.CommonResult;
import com.persagy.dmp.common.utils.ResultHelper;
import com.persagy.dmp.define.entity.DigitalEquipClassRel;
import com.persagy.dmp.define.entity.RelationDefine;
import com.persagy.dmp.mybatis.utils.ConditionUtil;
import com.persagy.dmp.rwd.define.dao.DigitalEquipClassRelMapper;
import com.persagy.dmp.rwd.define.service.DigitalEquipClassRelService;
import com.persagy.dmp.rwd.define.service.IRelationDefineService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/***
 * Description: 项目设备类关系逻辑处理类
 * @author : lijie
 * @date :2021/9/14 21:27
 * Update By lijie 2021/9/14 21:27
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class DigitalEquipClassRelServiceImpl extends ServiceImpl<DigitalEquipClassRelMapper, DigitalEquipClassRel>
implements DigitalEquipClassRelService {

    private final IRelationDefineService relationDefineService;

    /***
     * Description: 创建设备类关系对象
     * @param voList : 设备类关系对象列表
     * @return : com.persagy.dmp.define.entity.DigitalEquipClassRel
     * @author : lijie
     * @date :2021/9/14 21:09
     * Update By lijie 2021/9/14 21:09
     */
    @Override
    @Transactional(rollbackFor = BusinessException.class)
    public List<DigitalEquipClassRel> create(List<DigitalEquipClassRel> voList) {
        Set<String> calcNames = new HashSet<>();
        // 1.如果关系类型code与图类型编码为空且calcName为空则报错
        for (DigitalEquipClassRel vo : voList) {
            if (StrUtil.isNotBlank(vo.getCalcName())){
                calcNames.add(vo.getCalcName());
                continue;
            }
            if (StrUtil.isBlank(vo.getGraphCode()) || StrUtil.isBlank(vo.getRelCode())){
                throw new BusinessException(ResponseCode.A0402.getCode(),"缺少图类型编码和关系类型编码");
            }
        }
        // 2.根据名称填充图类型编码及关系类型编码
        Map<String, RelationDefine> relationDefineMap = new HashMap<>(16);
        if (CollUtil.isNotEmpty(calcNames)){
            // 根据名称查询图类型编码和关系类型编码
            List<RelationDefine> defines = queryRelationDefinesByRelNames(calcNames);
            if (CollUtil.isEmpty(defines)){
                throw new BusinessException(ResponseCode.A0402.getCode(),"关系类型编码不存在");
            }
            // 获得关系类型编码映射
            for (RelationDefine define : defines) {
                RelationDefine relationDefine = relationDefineMap.get(define.getName());
                if (null!=relationDefine){
                    throw new BusinessException(ResponseCode.A0402.getCode(),define.getName()+"关系类型编码存在多条");
                }
                relationDefineMap.put(define.getName(),define);
            }
        }
        // 3.填充数据
        LambdaUpdateWrapper<DigitalEquipClassRel> updateWrapper = new LambdaUpdateWrapper<>();
        for (DigitalEquipClassRel vo : voList) {
            if (StrUtil.isNotBlank(vo.getCalcName())){
                if(!relationDefineMap.containsKey(vo.getCalcName())){
                    throw new BusinessException(ResponseCode.A0402.getCode(),vo.getCalcName()+"关系类型编码不存在");
                }
                RelationDefine relationDefine = relationDefineMap.get(vo.getCalcName());
                vo.setGraphCode(relationDefine.getGraphCode());
                vo.setRelCode(relationDefine.getCode());
            }
            vo.setProjectId(AppContext.getContext().getProjectId());
            vo.setGroupCode(AppContext.getContext().getGroupCode());
            vo.setCreator(AppContext.getContext().getAccountId());
            updateWrapper.or(wrapper->{
                wrapper.eq(DigitalEquipClassRel::getGraphCode,vo.getGraphCode());
                wrapper.eq(DigitalEquipClassRel::getRelCode,vo.getRelCode());
                wrapper.eq(DigitalEquipClassRel::getProjectId,vo.getProjectId());
            });
        }
        // 4.逻辑删除历史数据
        DigitalEquipClassRel digitalEquipClassRel = new DigitalEquipClassRel();
        digitalEquipClassRel.setModifier(AppContext.getContext().getAccountId());
        digitalEquipClassRel.setModifiedTime(new PsDateTime());
        digitalEquipClassRel.setValid(0);
        this.update(digitalEquipClassRel,updateWrapper);
        this.saveBatch(voList);
        return voList;
    }
    /***
     * Description: 根据边名称查询边定义数据
     * @param calcNames :边名称列表
     * @return : java.util.List<com.persagy.dmp.define.entity.RelationDefine>
     * @author : lijie
     * @date :2021/9/15 11:41
     * Update By lijie 2021/9/15 11:41
     */
    private List<RelationDefine> queryRelationDefinesByRelNames(Set<String> calcNames) {
        if (CollUtil.isEmpty(calcNames)){
            return new ArrayList<>();
        }
        LambdaQueryWrapper<RelationDefine> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(RelationDefine::getName,calcNames);
        queryWrapper.eq(RelationDefine::getValid,true);
        return relationDefineService.queryByCondition(queryWrapper);
    }

    /***
     * Description: 根据条件查询设备类关系对象列表
     * @param criteria : 查询条件
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.define.entity.DigitalEquipClassRel>>
     * @author : lijie
     * @date :2021/9/14 21:14
     * Update By lijie 2021/9/14 21:14
     */
    @Override
    public CommonResult<List<DigitalEquipClassRel>> query(QueryCriteria criteria) {
        QueryWrapper<DigitalEquipClassRel> wrapper = new QueryWrapper<>();
        // 添加所属项目条件
        ConditionUtil.ensureProjectCriteriaDirectly(wrapper);
        // 转换查询条件
        QueryCriteriaHelper.toWrapper(wrapper, criteria, DigitalEquipClassRel.class);
        if(criteria.isOnlyCount()) {
            int total = count(wrapper);
            return ResultHelper.multi(new ArrayList<>(),total);
        }
        Page<DigitalEquipClassRel> page = page(QueryCriteriaHelper.toPage(criteria), wrapper);
        // 填充关系名称
        List<DigitalEquipClassRel> records = page.getRecords();
        if (CollUtil.isEmpty(records)){
            return ResultHelper.multi(new ArrayList<>(),page.getTotal());
        }
        // 获取图类型和边类型编码
        Set<String> graphCodes = records.stream()
                .map(DigitalEquipClassRel::getGraphCode)
                .collect(Collectors.toSet());
        Set<String> relCodes = records.stream()
                .map(DigitalEquipClassRel::getRelCode)
                .collect(Collectors.toSet());
        // {图类型编码_边类型编码:边类型对象}
        Map<String, RelationDefine> relCodeMap = relationDefineService.queryRelMapByCodes(graphCodes,relCodes);
        records.forEach(record->{
            String key = record.getGraphCode() + StrUtil.UNDERLINE + record.getRelCode();
            if (!relCodeMap.containsKey(key)){
                return;
            }
            record.setCalcName(relCodeMap.get(key).getName());
        });
        return ResultHelper.multi(page.getRecords(), page.getTotal());
    }
    /***
     * Description: 根据边关系名称查询项目对象类型关系列表
     * @param defineRequestData : 请求参数
     * @return : com.persagy.dmp.common.model.response.CommonResult<java.util.List<com.persagy.dmp.define.entity.DigitalEquipClassRel>>
     * @author : lijie
     * @date :2021/9/15 11:38
     * Update By lijie 2021/9/15 11:38
     */
    @Override
    public CommonResult<List<DigitalEquipClassRel>> queryListByRelNames(DefineRequestData defineRequestData) {
        Map<String, RelationDefine> defineMap = queryRelationDefineMapByRelNames(defineRequestData.getRelNames());
        LambdaQueryWrapper<DigitalEquipClassRel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DigitalEquipClassRel::getValid,true);
        queryWrapper.eq(DigitalEquipClassRel::getGroupCode,AppContext.getContext().getGroupCode());
        if (StrUtil.isNotBlank(AppContext.getContext().getProjectId())){
            queryWrapper.eq(DigitalEquipClassRel::getProjectId,AppContext.getContext().getProjectId());
        }
        Map<String, String> relNameMap = new HashMap<>(16);
        if (CollUtil.isNotEmpty(defineRequestData.getRelNames())){
            queryWrapper.and(wrapper->{
                Set<String> relNames = defineRequestData.getRelNames();
                for (String relName : relNames) {
                    if (!defineMap.containsKey(relName)){
                        continue;
                    }
                    RelationDefine relationDefine = defineMap.get(relName);
                    relNameMap.put(relationDefine.getGraphCode()+StrUtil.UNDERLINE+relationDefine.getCode(),relationDefine.getName());
                    wrapper.or(subWrapper->{
                        subWrapper.eq(DigitalEquipClassRel::getGraphCode,relationDefine.getGraphCode());
                        subWrapper.eq(DigitalEquipClassRel::getRelCode,relationDefine.getCode());
                    });
                }
            });
        }
        List<DigitalEquipClassRel> digitalEquipClassRels = this.list(queryWrapper);
        if (CollUtil.isEmpty(digitalEquipClassRels)){
            return ResultHelper.multi(new ArrayList<>(),0L);
        }
        // 填充名称
        digitalEquipClassRels.forEach(digitalEquipClassRel ->
                digitalEquipClassRel.setCalcName(relNameMap
                        .getOrDefault(digitalEquipClassRel.getGraphCode()+StrUtil.UNDERLINE+digitalEquipClassRel.getRelCode(),"")));
        return ResultHelper.multi(digitalEquipClassRels,digitalEquipClassRels.size());
    }
    /***
     * Description: 根据边类型名称
     * @param relNames : 
     * @return : java.util.Map<java.lang.String,com.persagy.dmp.define.entity.RelationDefine>  
     * @author : lijie
     * @date :2021/9/15 12:01
     * Update By lijie 2021/9/15 12:01
     */
    private Map<String, RelationDefine> queryRelationDefineMapByRelNames(Set<String> relNames) {
        if (CollUtil.isEmpty(relNames)){
            return new HashMap<>(16);
        }
        // 1.根据边类型名称查询边类型定义
        List<RelationDefine> defines = queryRelationDefinesByRelNames(relNames);
        if (CollUtil.isEmpty(defines)){
            return new HashMap<>(16);
        }
        // 获得名称与边类型的映射
        return defines.stream()
                .collect(Collectors
                        .toMap(RelationDefine::getName,define->define,(k1,k2)->k1));
    }
}




