package com.njcn.device.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.common.pojo.enums.common.ServerEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.device.enums.DeviceResponseEnum;
import com.njcn.device.enums.LineBaseEnum;
import com.njcn.device.mapper.DeptLineMapper;
import com.njcn.device.mapper.LineMapper;
import com.njcn.device.mapper.TreeMapper;
import com.njcn.device.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pojo.param.DeviceInfoParam;
import com.njcn.device.pojo.po.DeptLine;
import com.njcn.device.pojo.po.Line;
import com.njcn.device.pojo.vo.DeptLineTreeVO;
import com.njcn.device.pojo.vo.TerminalTree;
import com.njcn.device.service.TerminalTreeService;
import com.njcn.system.api.AreaFeignClient;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.enums.StatisticsEnum;
import com.njcn.system.pojo.po.Area;
import com.njcn.system.pojo.po.DictData;
import com.njcn.web.utils.GeneralUtil;
import com.njcn.web.utils.RequestUtil;
import io.swagger.models.auth.In;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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

/**
 * pqs
 * 终端设备树
 *
 * @author cdf
 * @date 2021/7/19
 */
@Service
@AllArgsConstructor
public class TerminalTreeServiceImpl implements TerminalTreeService {

    private final LineMapper lineMapper;

    private final AreaFeignClient areaFeignClient;

    private final DicDataFeignClient dicDataFeignClient;

    private final DeptLineMapper deptLineMapper;

    private final GeneralDeviceService generalDeviceService;

    private final TreeMapper treeMapper;

    /**
     * 台账页面终端树
     *
     * @author cdf
     * @date 2022/1/13
     */
    @Override
    public List<TerminalTree> getTerminalTree() {
        List<TerminalTree> taiZhang = new ArrayList<>();
        List<TerminalTree> allList = lineMapper.getAllList();
        List<TerminalTree> projectList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROJECT_LEVEL.getCode())).sorted(Comparator.comparing(TerminalTree::getSort)).collect(Collectors.toList());
        List<TerminalTree> provinceList = lineMapper.getProvinceList(null, 0);
        List<TerminalTree> gdList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.GD_LEVEL.getCode())).sorted(Comparator.comparing(TerminalTree::getSort)).collect(Collectors.toList());
        List<TerminalTree> subList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_LEVEL.getCode())).sorted(Comparator.comparing(TerminalTree::getSort)).collect(Collectors.toList());
        List<TerminalTree> devList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.DEVICE_LEVEL.getCode())).sorted(Comparator.comparing(TerminalTree::getSort)).collect(Collectors.toList());
        List<TerminalTree> subvList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_V_LEVEL.getCode())).sorted(Comparator.comparing(TerminalTree::getSort)).collect(Collectors.toList());
        List<TerminalTree> lineList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.LINE_LEVEL.getCode())).sorted(Comparator.comparing(TerminalTree::getSort)).collect(Collectors.toList());


        subvList.forEach(subv -> subv.setChildren(getChildren(subv, lineList)));
        devList.forEach(dev -> dev.setChildren(getChildren(dev, subvList)));
        subList.forEach(sub -> sub.setChildren(getChildren(sub, devList)));
        gdList.forEach(gd -> gd.setChildren(getChildren(gd, subList)));
        provinceList.forEach(province -> province.setChildren(getChildren(province, gdList)));
        projectList.forEach(project -> project.setChildren(getChildren(project, provinceList)));

        if (CollectionUtil.isNotEmpty(allList)) {
            TerminalTree terminalTree = new TerminalTree();
            terminalTree.setId("9999999");
            terminalTree.setLevel(0);
            terminalTree.setName("台账管理");
            if (CollectionUtil.isNotEmpty(projectList)) {
                terminalTree.setChildren(projectList);
            }
            taiZhang.add(terminalTree);
        }
        return taiZhang;
    }

    /**
     * 5层树排除设备 母线监测点合并
     *
     * @author cdf
     * @date 2022/1/13
     */
    @Override
    public List<TerminalTree> getTerminalTreeForFive(DeviceInfoParam deviceInfoParam) {
        deviceInfoParam.setDeptIndex(RequestUtil.getDeptIndex());
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceService.getDeviceInfo(deviceInfoParam, Stream.of(0).collect(Collectors.toList()), Stream.of(1).collect(Collectors.toList()));
        if (CollectionUtil.isNotEmpty(generalDeviceDTOList)) {
            List<TerminalTree> taiZhang = new ArrayList<>();
            for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
                TerminalTree terminalTree = new TerminalTree();
                if (CollectionUtils.isEmpty(generalDeviceDTO.getLineIndexes())) {
                    continue;
                }
                List<TerminalTree> proList = treeMapper.getProvinceList(generalDeviceDTO.getGdIndexes());
                List<TerminalTree> gdList = treeMapper.getGdList(generalDeviceDTO.getGdIndexes());
                List<TerminalTree> subList = treeMapper.getSubList(generalDeviceDTO.getSubIndexes());
                List<TerminalTree> lineList = treeMapper.getLineList(generalDeviceDTO.getLineIndexes());
                //处理变电站
                dealChildrenData(subList,lineList,true);
                //处理供电公司
                dealChildrenData(gdList,subList,false);
                if (deviceInfoParam.getStatisticalType().getCode().equalsIgnoreCase(StatisticsEnum.POWER_NETWORK.getCode())) {
                    terminalTree.setChildren(gdList);
                } else {
                    //还需要额外处理省会
                    dealChildrenData(proList,gdList,false);
                    terminalTree.setChildren(proList);
                }
                terminalTree.setId(generalDeviceDTO.getIndex());
                terminalTree.setName(generalDeviceDTO.getName());
                terminalTree.setLevel(0);
                taiZhang.add(terminalTree);
            }
            return taiZhang;
        } else {
           return new ArrayList<>();
        }
    }

    private void dealChildrenData(List<TerminalTree> targetData, List<TerminalTree> childrenData, boolean isLine) {
        Map<String,List<TerminalTree>> groupLine;
        if(isLine){
            groupLine = childrenData.stream().collect(Collectors.groupingBy(terminalTree -> {
                String[] pid = terminalTree.getPids().split(",");
                return pid[LineBaseEnum.SUB_LEVEL.getCode()];
            }));
        }else{
            groupLine = childrenData.stream().collect(Collectors.groupingBy(TerminalTree::getPid));
        }
        targetData=targetData.stream().peek(terminalTree -> {
            terminalTree.setChildren(groupLine.get(terminalTree.getId()));
        }).collect(Collectors.toList());
    }


    @Override
    public List<DeptLineTreeVO> getDeptBindDeptLineTree(String deptId, Integer deptType, String id, Integer type) {
        List<DeptLineTreeVO> deptLineTreeVOS = new ArrayList<>();
        /**
         * 非自定义树
         */
        if (deptType.equals(0)) {
            DeptLineTreeVO deptLineTreeVO = new DeptLineTreeVO();
            deptLineTreeVO.setNothingBindTree(getNothingDeptBindDeptLineTree(id, type));
            deptLineTreeVO.setOtherBindTree(getOtherDeptBindDeptLineTree(deptId, id, type));
            deptLineTreeVO.setMyselfBindTree(getMyselfDeptBindDeptLineTree(deptId, id, type));
            deptLineTreeVOS.add(deptLineTreeVO);
        } else {
            /**
             * 自定义树
             */
            DeptLineTreeVO deptLineTreeVO = new DeptLineTreeVO();
            deptLineTreeVO.setNothingBindTree(setNothingBindComDeptTree(id, type));
            deptLineTreeVO.setMyselfBindTree(getMyselfDeptBindDeptLineTree(deptId, id, type));
            deptLineTreeVOS.add(deptLineTreeVO);
        }
        return deptLineTreeVOS;
    }


    /**
     * 获取全部子节点
     *
     * @author cdf
     * @date 2021/7/19
     */
    public List<TerminalTree> getChildren(TerminalTree item, List<TerminalTree> all) {
        return all.stream().filter(allItem -> allItem.getPid().equals(item.getId())).collect(Collectors.toList());
    }

    /**
     * 未绑定监测点树
     *
     * @param id
     * @param type
     * @return
     */
    public List<TerminalTree> getNothingDeptBindDeptLineTree(String id, Integer type) {

        List<TerminalTree> nothingBindTree = new ArrayList<>();
        List<TerminalTree> allList = lineMapper.getAllList();
        HttpResult<Area> area = areaFeignClient.areaPro(id, type);
        Area areaDetail = area.getData();
        String areaId = areaDetail.getId();

        if (CollectionUtil.isNotEmpty(allList)) {
            List<TerminalTree> projectList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROJECT_LEVEL.getCode()) && item.getId().equals(lineMapper.selectProject(areaId))).collect(Collectors.toList());
            List<TerminalTree> provinceList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROVINCE_LEVEL.getCode()) && item.getName().equals(areaId)).collect(Collectors.toList());
            for (TerminalTree terminalTree : provinceList) {
                terminalTree.setName(lineMapper.getProviceName(terminalTree.getName()));
            }
            List<TerminalTree> gdList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.GD_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> devList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.DEVICE_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subvList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_V_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> lineList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.LINE_LEVEL.getCode())).collect(Collectors.toList());
            List<String> deptLineList = deptLineMapper.getAllBindLine();
            /**
             * 取出未绑定的监测点
             */
            List<TerminalTree> lineNoBindList = new ArrayList<>();
            for (int i = 0; i < lineList.size(); i++) {
                if (!deptLineList.contains(lineList.get(i).getId())) {
                    lineNoBindList.add(lineList.get(i));
                }
            }
            for (TerminalTree sub : subList) {
                List<TerminalTree> lineTemp = new ArrayList<>();
                List<TerminalTree> devTemp = devList.stream().filter(d -> d.getPid().equals(sub.getId())).collect(Collectors.toList());

                for (TerminalTree dev : devTemp) {
                    List<TerminalTree> subvTemp = subvList.stream().filter(d -> d.getPid().equals(dev.getId())).collect(Collectors.toList());

                    for (TerminalTree subv : subvTemp) {
                        List<TerminalTree> lineRes = lineNoBindList.stream().filter(d -> d.getPid().equals(subv.getId())).map(
                                (item) ->
                                {
                                    String name = subv.getName() + "_" + item.getName();
                                    item.setName(name);
                                    item.setPid(sub.getId());
                                    return item;
                                }).collect(Collectors.toList());
                        lineTemp.addAll(lineRes);

                    }
                }
                sub.setChildren(lineTemp);
            }

            gdList.stream().peek(gd -> {
                gd.setChildren(getChildren(gd, subList));
                gd.setLevel(2);
            }).collect(Collectors.toList());
            provinceList.stream().peek(province -> {
                province.setChildren(getChildren(province, gdList));
                province.setLevel(1);
            }).collect(Collectors.toList());
            nothingBindTree = projectList.stream().peek(project -> {
                project.setChildren(getChildren(project, provinceList));
                project.setLevel(0);
            }).collect(Collectors.toList());

        }
        return nothingBindTree;
    }

    /**
     * 未绑定监测点树(自定义)
     *
     * @param id
     * @param type
     * @return
     */
    public List<TerminalTree> setNothingBindComDeptTree(String id, Integer type) {
        List<TerminalTree> nothingBindTree = new ArrayList<>();
        List<TerminalTree> allList = lineMapper.getAllList();
        HttpResult<Area> area = areaFeignClient.areaPro(id, type);
        Area areaDetail = area.getData();
        String areaId = areaDetail.getId();

        if (CollectionUtil.isNotEmpty(allList)) {
            List<TerminalTree> projectList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROJECT_LEVEL.getCode()) && item.getId().equals(lineMapper.selectProject(areaId))).collect(Collectors.toList());
            List<TerminalTree> provinceList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROVINCE_LEVEL.getCode()) && item.getName().equals(areaId)).collect(Collectors.toList());
            for (TerminalTree terminalTree : provinceList) {
                terminalTree.setName(lineMapper.getProviceName(terminalTree.getName()));
            }
            List<TerminalTree> gdList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.GD_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> devList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.DEVICE_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subvList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_V_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> lineList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.LINE_LEVEL.getCode())).collect(Collectors.toList());
            for (TerminalTree sub : subList) {
                List<TerminalTree> lineTemp = new ArrayList<>();
                List<TerminalTree> devTemp = devList.stream().filter(d -> d.getPid().equals(sub.getId())).collect(Collectors.toList());

                for (TerminalTree dev : devTemp) {
                    List<TerminalTree> subvTemp = subvList.stream().filter(d -> d.getPid().equals(dev.getId())).collect(Collectors.toList());

                    for (TerminalTree subv : subvTemp) {
                        List<TerminalTree> lineRes = lineList.stream().filter(d -> d.getPid().equals(subv.getId())).map(
                                (item) ->
                                {
                                    String name = subv.getName() + "_" + item.getName();
                                    item.setPid(sub.getId());
                                    item.setName(name);
                                    return item;
                                }).collect(Collectors.toList());
                        lineTemp.addAll(lineRes);

                    }
                }
                sub.setChildren(lineTemp);
            }

            gdList.stream().peek(gd -> {
                gd.setChildren(getChildren(gd, subList));
                gd.setLevel(2);
            }).collect(Collectors.toList());
            provinceList.stream().peek(province -> {
                province.setChildren(getChildren(province, gdList));
                province.setLevel(1);
            }).collect(Collectors.toList());
            nothingBindTree = projectList.stream().peek(project -> {
                project.setChildren(getChildren(project, provinceList));
                project.setLevel(0);
            }).collect(Collectors.toList());

        }
        return nothingBindTree;
    }

    /**
     * 其他绑定绑定监测点树
     *
     * @param id
     * @param type
     * @return
     */
    public List<TerminalTree> getOtherDeptBindDeptLineTree(String deptId, String id, Integer type) {
        //其他绑定监测点树
        List<TerminalTree> otherBindTree = new ArrayList<>();
        List<TerminalTree> allList = lineMapper.getAllList();
        HttpResult<Area> area = areaFeignClient.areaPro(id, type);
        Area areaDetail = area.getData();
        String areaId = areaDetail.getId();

        if (CollectionUtil.isNotEmpty(allList)) {
            List<TerminalTree> projectList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROJECT_LEVEL.getCode()) && item.getId().equals(lineMapper.selectProject(areaId))).collect(Collectors.toList());
            List<TerminalTree> provinceList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROVINCE_LEVEL.getCode()) && item.getName().equals(areaId)).collect(Collectors.toList());
            for (TerminalTree terminalTree : provinceList) {
                terminalTree.setName(lineMapper.getProviceName(terminalTree.getName()));
            }
            List<TerminalTree> gdList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.GD_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> devList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.DEVICE_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subvList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_V_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> lineList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.LINE_LEVEL.getCode())).collect(Collectors.toList());
            List<String> deptLineList = deptLineMapper.getOtherBindLine(deptId);

            List<TerminalTree> lineOther = new ArrayList<>();
            for (int i = 0; i < lineList.size(); i++) {
                if (deptLineList.contains(lineList.get(i).getId())) {
                    lineOther.add(lineList.get(i));
                }
            }
            for (TerminalTree sub : subList) {
                List<TerminalTree> lineTemp = new ArrayList<>();
                List<TerminalTree> devTemp = devList.stream().filter(d -> d.getPid().equals(sub.getId())).collect(Collectors.toList());

                for (TerminalTree dev : devTemp) {
                    List<TerminalTree> subvTemp = subvList.stream().filter(d -> d.getPid().equals(dev.getId())).collect(Collectors.toList());

                    for (TerminalTree subv : subvTemp) {
                        List<TerminalTree> lineRes = lineOther.stream().filter(d -> d.getPid().equals(subv.getId())).map(
                                (item) ->
                                {
                                    String name = subv.getName() + "_" + item.getName();
                                    item.setName(name);
                                    item.setPid(sub.getId());
                                    return item;
                                }).collect(Collectors.toList());
                        lineTemp.addAll(lineRes);

                    }
                }
                sub.setChildren(lineTemp);

            }

            gdList.stream().peek(gd -> {
                gd.setChildren(getChildren(gd, subList));
                gd.setLevel(2);
            }).collect(Collectors.toList());
            provinceList.stream().peek(province -> {
                province.setChildren(getChildren(province, gdList));
                province.setLevel(1);
            }).collect(Collectors.toList());
            otherBindTree = projectList.stream().peek(project -> {
                project.setChildren(getChildren(project, provinceList));
                project.setLevel(0);
            }).collect(Collectors.toList());
        }
        return otherBindTree;
    }

    /**
     * 本身绑定绑定监测点树
     *
     * @param id
     * @param type
     * @return
     */
    public List<TerminalTree> getMyselfDeptBindDeptLineTree(String deptId, String id, Integer type) {
        //本身绑定监测点树
        List<TerminalTree> myselfBindTree = new ArrayList<>();
        List<TerminalTree> allList = lineMapper.getAllList();
        HttpResult<Area> area = areaFeignClient.areaPro(id, type);
        Area areaDetail = area.getData();
        String areaId = areaDetail.getId();

        if (CollectionUtil.isNotEmpty(allList)) {
            List<TerminalTree> projectList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROJECT_LEVEL.getCode()) && item.getId().equals(lineMapper.selectProject(areaId))).collect(Collectors.toList());
            List<TerminalTree> provinceList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.PROVINCE_LEVEL.getCode()) && item.getName().equals(areaId)).collect(Collectors.toList());
            for (TerminalTree terminalTree : provinceList) {
                terminalTree.setName(lineMapper.getProviceName(terminalTree.getName()));
            }
            List<TerminalTree> gdList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.GD_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> devList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.DEVICE_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> subvList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.SUB_V_LEVEL.getCode())).collect(Collectors.toList());
            List<TerminalTree> lineList = allList.stream().filter(item -> item.getLevel().equals(LineBaseEnum.LINE_LEVEL.getCode())).collect(Collectors.toList());
            List<String> deptLineList = deptLineMapper.getMyselfBindLine(deptId);

            List<TerminalTree> lineMyself = new ArrayList<>();
            for (int i = 0; i < lineList.size(); i++) {
                if (deptLineList.contains(lineList.get(i).getId())) {
                    lineMyself.add(lineList.get(i));
                }
            }


            for (TerminalTree sub : subList) {
                List<TerminalTree> lineTemp = new ArrayList<>();
                List<TerminalTree> devTemp = devList.stream().filter(d -> d.getPid().equals(sub.getId())).collect(Collectors.toList());

                for (TerminalTree dev : devTemp) {
                    List<TerminalTree> subvTemp = subvList.stream().filter(d -> d.getPid().equals(dev.getId())).collect(Collectors.toList());

                    for (TerminalTree subv : subvTemp) {
                        List<TerminalTree> lineRes = lineMyself.stream().filter(d -> d.getPid().equals(subv.getId())).map(
                                (item) ->
                                {
                                    String name = subv.getName() + "_" + item.getName();
                                    item.setName(name);
                                    item.setPid(sub.getId());
                                    return item;
                                }).collect(Collectors.toList());
                        lineTemp.addAll(lineRes);

                    }
                }
                sub.setChildren(lineTemp);

            }

            gdList.stream().peek(gd -> {
                gd.setChildren(getChildren(gd, subList));
                gd.setLevel(2);
            }).collect(Collectors.toList());
            provinceList.stream().peek(province -> {
                province.setChildren(getChildren(province, gdList));
                province.setLevel(1);
            }).collect(Collectors.toList());
            myselfBindTree = projectList.stream().peek(project -> {
                project.setChildren(getChildren(project, provinceList));
                project.setLevel(0);
            }).collect(Collectors.toList());
        }
        return myselfBindTree;
    }


}
