package com.yeejoin.equipmanage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.dto.OrgMenuDto;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.DictionarieValueModel;
import com.yeejoin.equipmanage.common.dto.AreaDto;
import com.yeejoin.equipmanage.common.dto.OrgUsrDto;
import com.yeejoin.equipmanage.common.entity.Area;
import com.yeejoin.equipmanage.common.entity.EquipmentSpecific;
import com.yeejoin.equipmanage.common.entity.SourceFile;
import com.yeejoin.equipmanage.common.utils.StringUtil;
import com.yeejoin.equipmanage.common.utils.TreeNodeUtil;
import com.yeejoin.equipmanage.common.vo.AreaResquest;
import com.yeejoin.equipmanage.common.vo.UnitAreaTreeVo;
import com.yeejoin.equipmanage.context.SpringContextHolder;
import com.yeejoin.equipmanage.event.SynAreaRiskEvent;
import com.yeejoin.equipmanage.mapper.AreaMapper;
import com.yeejoin.equipmanage.operation.AreaSynRiskOperator;
import com.yeejoin.equipmanage.service.IAreaService;
import com.yeejoin.equipmanage.service.IEqSourceFileService;
import com.yeejoin.equipmanage.service.IEquipmentSpecificSerivce;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.Bean;

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

/**
 * 区域 服务实现类
 *
 * @author duanwei
 * @date 2021-04-27
 */
@Service
public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements IAreaService {

    @Autowired
    @Lazy
    private IEqSourceFileService iEqSourceFileService;

    @Autowired
    @Lazy
    private IEquipmentSpecificSerivce iEquipmentSpecificSerivce;

    @Autowired
    private AreaMapper areaMapper;

    @Value("${systemctl.dict.area-type}")
    private String areaType;


    @Autowired
    JCSRemoteService jcsRemoteService;

    @Value("${auth-key-area:area_info}")
    private String authKey;


    @Override
    public List<UnitAreaTreeVo> getAreaTreeVoByBizOrgCode(String bizOrgCode) {
        List<UnitAreaTreeVo> areaTreeList = new ArrayList<>();
        // 查询平台区域数据字典
        FeignClientResult<List<DictionarieValueModel>> dictValues = Systemctl.dictionarieClient.dictValues(areaType);
        if (dictValues != null) {
            List<DictionarieValueModel> values = dictValues.getResult();
            // 根据区域类型查询子节点
            if (values != null && values.size() > 0) {
                for (DictionarieValueModel dictionarieValueModel : values) {
                    UnitAreaTreeVo areaTreeVo = new UnitAreaTreeVo();
                    long parentId = Long.parseLong(dictionarieValueModel.getDictDataKey());
                    areaTreeVo.setId(parentId);
                    areaTreeVo.setName(dictionarieValueModel.getDictDataValue());
                    areaTreeVo.setChildren(getChildrenByBizOrgCode(parentId, bizOrgCode));
                    areaTreeList.add(areaTreeVo);
                }
            }
        }
        return areaTreeList;
    }

    /**
     * 根据父节点和bizOrgCode查询子节点赋值
     *
     * @param parentId
     * @return
     */
    public List<UnitAreaTreeVo> getChildrenByBizOrgCode(Long parentId, String bizOrgCode) {
        List<UnitAreaTreeVo> areaTreeVos = new ArrayList<>();
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getParentId, parentId);
        queryWrapper.eq(Area::getIsDelete, false);
        if (StringUtil.isNotEmpty(bizOrgCode)) {
            queryWrapper.likeRight(Area::getBizOrgCode, bizOrgCode);
        }
        return getUnitAreaTreeVos(parentId, areaTreeVos, queryWrapper);
    }

    private List<UnitAreaTreeVo> getUnitAreaTreeVos(Long parentId, List<UnitAreaTreeVo> areaTreeVos, LambdaQueryWrapper<Area> queryWrapper) {
        List<Area> areas = this.baseMapper.selectList(queryWrapper);
        if (areas != null && areas.size() > 0) {
            for (Area area : areas) {
                UnitAreaTreeVo areaTreeVo = new UnitAreaTreeVo();
                areaTreeVo.setId(area.getId());
                areaTreeVo.setName(area.getName());
                areaTreeVo.setBizOrgCode(area.getOrgCode());
                areaTreeVo.setParentId(parentId);
                // 查询子节点赋值
                areaTreeVo.setChildren(getChildren(area.getId()));
                areaTreeVos.add(areaTreeVo);
            }
        }
        return areaTreeVos;
    }

    @Override
    public List<UnitAreaTreeVo> getAreaTreeVoById(long id, String bizOrgCode) {
        List<UnitAreaTreeVo> listTree = new ArrayList<>();
        if (id == -1) {
            listTree = getAreaTreeListVo();
        } else {
            listTree = getChildrenz(id);
        }
        return listTree;
    }

    /**
     * 根据父节点查询子节点赋值
     *
     * @param parentId
     * @return
     */
    public List<UnitAreaTreeVo> getChildrenz(Long parentId) {
        List<UnitAreaTreeVo> areaTreeVos = new ArrayList<>();
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getIsDelete, false);
        queryWrapper.eq(Area::getId, parentId);
        return getUnitAreaTreeVos(parentId, areaTreeVos, queryWrapper);
    }

    /**
     * 根据父节点查询子节点赋值
     *
     * @param parentId
     * @return
     */
    public List<UnitAreaTreeVo> getChildren(Long parentId) {
        List<UnitAreaTreeVo> areaTreeVos = new ArrayList<>();
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getParentId, parentId);
        queryWrapper.eq(Area::getIsDelete, false);
        return getUnitAreaTreeVos(parentId, areaTreeVos, queryWrapper);
    }

    /**
     * 分页
     *
     * @param
     * @param
     * @return
     */
    @Override
    public IPage areaList(Page page, Area area) {
        long id = area.getParentId();
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        List<UnitAreaTreeVo> list = new ArrayList<>();
        list = treeMenuList(getAreaTreeListVo(), id);
        List<Long> parentIdSet = list.stream().map(vo -> vo.getId()).collect(Collectors.toList());
        if (StringUtil.isNotEmpty(area.getBizOrgCode())) {
            queryWrapper.likeRight(Area::getBizOrgCode, area.getBizOrgCode());
        }
        queryWrapper.eq(Area::getIsDelete, false);
        if (parentIdSet.size() > 0) {
            queryWrapper.in(Area::getParentId, parentIdSet);
            if (0 != area.getParentId()) {
                queryWrapper.or().eq(Area::getId, id);
            }
        }
        IPage pageArea = this.baseMapper.selectMapsPage(page, queryWrapper);

        // 查询平台区域数据字典
        FeignClientResult<List<DictionarieValueModel>> dictValues = Systemctl.dictionarieClient.dictValues(areaType);
        if (pageArea != null) {
            if (pageArea.getRecords() != null && pageArea.getRecords().size() > 0) {
                for (Object areas : pageArea.getRecords()) {
                    Map<String, Object> map = (Map<String, Object>) areas;
                    if (dictValues != null) {
                        List<DictionarieValueModel> values = dictValues.getResult();
                        // 根据区域类型查询子节点
                        if (values != null && values.size() > 0) {
                            for (DictionarieValueModel dictionarieValueModel : values) {
                                if (dictionarieValueModel.getDictDataKey().equals(map.get("type"))) {
                                    map.put("typeName", dictionarieValueModel.getDictDataValue());
                                }
                            }
                        }
                    }
                    List<SourceFile> sourceFiles = iEqSourceFileService.findBySourceId(Long.parseLong(String.valueOf(map.get("id"))));
                    map.put("files", sourceFiles);
                }
            }
        }
        return pageArea;
    }

    /**
     * 获取某个父节点下面的所有子节点
     *
     * @param list
     * @param pid
     * @return
     */
    public static List<UnitAreaTreeVo> treeMenuList(List<UnitAreaTreeVo> list, Long pid) {
        List<UnitAreaTreeVo> voList = new ArrayList<>();
        for (UnitAreaTreeVo vo : list) {
            //遍历出父id等于参数的id，add进子节点集合
            if (!ObjectUtils.isEmpty(vo.getParentId()) && 0 != vo.getParentId() && Long.valueOf(vo.getParentId()) == pid) {
                //递归遍历下一级
                treeMenuList(list, Long.valueOf(vo.getId()));
                voList.add(vo);
            }
        }
        return voList;
    }

    @Override
    public List<UnitAreaTreeVo> getAreaTreeListVo() {
        // 获取公司list
        List<OrgUsrDto> orgCompanyLists = jcsRemoteService.getCompanyDeptListWithAuth(authKey, "COMPANY");
        if (orgCompanyLists.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Long> orgMap = orgCompanyLists.stream().collect(Collectors.toMap(OrgUsrDto::getBizOrgCode, OrgUsrDto::getSequenceNbr));
        List<UnitAreaTreeVo> orgTreeList = orgCompanyLists.stream()
                .map(orgUsrDto -> {
                    UnitAreaTreeVo vo = new UnitAreaTreeVo();
                    vo.setId((orgUsrDto.getSequenceNbr()));
                    vo.setName(orgUsrDto.getBizOrgName());
                    vo.setType(orgUsrDto.getBizOrgType());
                    vo.setBizOrgCode(orgUsrDto.getBizOrgCode());
                    vo.setBizOrgName(orgUsrDto.getBizOrgName());
                    vo.setParentId(StringUtil.isNotEmpty(orgUsrDto.getParentId()) ? Long.parseLong(orgUsrDto.getParentId()) : 0);
                    return vo;
                }).collect(Collectors.toList());

        // 根据bizOrgCode获取区域list
        List<String> bizOrgCodes = orgTreeList.stream().map(UnitAreaTreeVo::getBizOrgCode).collect(Collectors.toList());
        LambdaQueryWrapper<Area> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Area::getIsDelete, false);
        wrapper.in(Area::getBizOrgCode, bizOrgCodes);
        List<Area> areaEntityList = this.baseMapper.selectList(wrapper);
        List<UnitAreaTreeVo> areaTreeVoList = areaEntityList.stream()
                .map(area -> {
                    UnitAreaTreeVo vo = new UnitAreaTreeVo();
                    vo.setId(area.getId());
                    vo.setName(area.getName());
                    vo.setType("area");
                    vo.setBizOrgCode(area.getBizOrgCode());
                    vo.setBizOrgName(area.getBizOrgName());
                    vo.setParentId(area.getParentId().equals(0L) ? orgMap.get(area.getBizOrgCode()) : area.getParentId());
                    return vo;
                }).collect(Collectors.toList());
        orgTreeList.addAll(areaTreeVoList);
        return orgTreeList.stream().filter(o -> orgTreeList.stream().noneMatch(a -> a.getId().equals(o.getParentId()))).peek(a -> {
            a.setChildren(getChildrenFromData(a.getId(), orgTreeList));
        }).collect(Collectors.toList());
    }

    private List<UnitAreaTreeVo> getChildrenFromData(Long parentId, List<UnitAreaTreeVo> areaTreeList) {
        return areaTreeList.stream().filter(a -> parentId.equals(a.getParentId())).peek(e -> e.setChildren(getChildrenFromData(e.getId(), areaTreeList))).collect(Collectors.toList());
    }


    @Override
    public List<OrgMenuDto> companyDeptTree() {
        return jcsRemoteService.getCompanyDeptTreeWithAuth(authKey, "COMPANY");
    }

    /**
     * 根据父节点查询所有子节点parentId
     *
     * @param parentId
     * @return
     */
    public Set<Long> getChildrenId(Long parentId) {
        Set<Long> idSet = new HashSet<>();
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getParentId, parentId);
        queryWrapper.eq(Area::getIsDelete, false);
        List<Area> areas = this.baseMapper.selectList(queryWrapper);
        if (areas != null && areas.size() > 0) {
            for (Area area : areas) {
                idSet.add(area.getParentId());
                idSet.addAll(getChildrenId(area.getId()));
            }
        }
        return idSet;
    }


    @Override
    @Transactional
    public Object saveArea(AreaResquest areaResquest) {
        // 保存基础数据
        Area area = new Area();
        BeanUtils.copyProperties(areaResquest, area);
        boolean flag = this.save(area);
        // 保存图片
        long id = area.getId();
        if (areaResquest.getSourceFiles() != null) {
            iEqSourceFileService.saveSourceFile(id, areaResquest.getSourceFiles());
        }
        // 风险同步
        if (areaResquest.getRiskPointId() != null) {
            areaResquest.setId(id);
            SpringContextHolder.publishEvent(new SynAreaRiskEvent(this, areaResquest, AreaSynRiskOperator.ADD.getType()));
        }
        return flag;
    }

    @Override
    @Transactional
    public Object updateArea(AreaResquest areaResquest) {
        // 更新基础数据
        Area areaOld = this.baseMapper.selectById(areaResquest.getId());
        String bizOrgCode = areaResquest.getBizOrgCode();
        if (StringUtil.isNotEmpty(areaOld.getBizOrgCode()) && !areaOld.getBizOrgCode().equals(bizOrgCode)) {
            LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Area::getParentId, areaOld.getId());
            List<Area> list = this.baseMapper.selectList(queryWrapper);
            for (Area area : list) {
                area.setBizOrgCode(areaResquest.getBizOrgCode());
                area.setBizOrgName(areaResquest.getBizOrgName());
                this.baseMapper.updateById(area);
            }
        }
        Area area = new Area();
        Bean.copyExistPropertis(areaResquest, area);
        boolean flag = this.updateById(area);
        // 保存图片
        long id = area.getId();
        if (areaResquest.getSourceFiles() != null) {
            iEqSourceFileService.saveSourceFile(id, areaResquest.getSourceFiles());
        }
        // 风险同步
        //第1种情况：之前未绑定，编辑时绑定
        if (areaOld.getRiskPointId() == null && areaResquest.getRiskPointId() != null) {
            SpringContextHolder.publishEvent(new SynAreaRiskEvent(this, areaResquest, AreaSynRiskOperator.UPDATE.getType()));
        }
        //第2种情况：之前已绑定，编辑时清除绑定
        if (areaOld.getRiskPointId() != null && areaResquest.getRiskPointId() == null) {
            areaResquest.setRiskPointId(areaOld.getRiskPointId());
            SpringContextHolder.publishEvent(new SynAreaRiskEvent(this, areaResquest, AreaSynRiskOperator.UPDATE.getType()));
        }
        //第3种情况：换绑
        if (areaOld.getRiskPointId() != null && areaResquest.getRiskPointId() != null && !areaOld.getRiskPointId().equals(areaResquest.getRiskPointId())) {
            SpringContextHolder.publishEvent(new SynAreaRiskEvent(this, areaResquest, AreaSynRiskOperator.UPDATE.getType()));
        }
        //第4种情况: 始终未绑定,不做任何操作
        if (areaOld.getRiskPointId() == null && areaResquest.getRiskPointId() == null) {
            return flag;
        }
        return flag;
    }

    @Override
    public int deleteArea(Long instanceId) {
        Area area = new Area();
        // 查询是否被引用
        LambdaQueryWrapper<EquipmentSpecific> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EquipmentSpecific::getAreaId, instanceId);
        List<EquipmentSpecific> equipmentSpecificList = iEquipmentSpecificSerivce.list(queryWrapper);
        if (equipmentSpecificList != null && equipmentSpecificList.size() > 0) {
            return -1;
        } else {
            area.setIsDelete(true);
            area.setId(instanceId);
            return this.baseMapper.updateById(area);
        }
    }

    @Override
    public Map<String, Object> getById(Long instanceId) {
        Area area = this.baseMapper.selectById(instanceId);
        List<SourceFile> sourceFiles = iEqSourceFileService.findBySourceId(instanceId);
        Map<String, Object> map = new HashMap<>();
        map.put("area", area);
        map.put("files", sourceFiles);
        return map;
    }

    @Override
    @Transactional
    public List<AreaDto> getAreaTierTree(Integer tier) {
        List<AreaDto> list = areaMapper.findByIsDeleted(0);
        if (!CollectionUtils.isEmpty(list)) {
            return TreeNodeUtil.assembleTree(list, tier);
        }
        return Lists.newArrayList();
    }
}
