package com.hw.ems.report.service.impl;

//import com.baomidou.dynamic.datasource.annotation.DS;
import com.hw.common.core.utils.sortReportUitls;
import com.hw.common.core.utils.DateUtils;
import com.hw.common.core.utils.StringUtils;
import com.hw.ems.base.domain.BaseLineLoss;
import com.hw.ems.base.domain.BaseLineMonitor;
import com.hw.ems.base.domain.BaseMonitorInfo;
import com.hw.ems.base.domain.BaseTypeRelation;
import com.hw.ems.base.mapper.BaseLineLossMapper;
import com.hw.ems.base.mapper.BaseLineMonitorMapper;
import com.hw.ems.base.mapper.BaseMonitorInfoMapper;
import com.hw.ems.base.mapper.BaseTypeRelationMapper;
import com.hw.ems.base.service.IBaseMonitorInfoService;
import com.hw.ems.report.domain.ExportReport;
import com.hw.ems.report.domain.ReportPointDnb;
import com.hw.ems.report.domain.ReportPointWater;
import com.hw.ems.report.mapper.ReportPointDnbMapper;
import com.hw.ems.report.mapper.ReportPointWaterMapper;
import com.hw.ems.report.service.IDataAnalysisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.hw.ems.base.service.impl.BaseLineMonitorServiceImpl.getLowestLevelLineMonitorList;


/**
 * 水整点数据Service业务层处理
 *
 * @author YinQ
 * @date 2023-04-09
 */
@Service
public class DataAnalysisServiceImpl implements IDataAnalysisService {
    @Autowired
    private ReportPointWaterMapper reportPointWaterMapper;

    @Autowired
    private ReportPointDnbMapper reportPointDnbMapper;

    @Autowired
    private IBaseMonitorInfoService baseMonitorInfoService;

    @Autowired
    private BaseLineLossMapper baseLineLossMapper;

    @Autowired
    private BaseMonitorInfoMapper baseMonitorInfoMapper;

    @Autowired
    private BaseTypeRelationMapper baseTypeRelationMapper;

    @Autowired
    private BaseLineMonitorMapper baseLineMonitorMapper;


    /**
     * 环比分析返回数据
     *
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public Map<String, Object> energyMomAnalysisData(Map paramMap) {
        HashMap<String, Object> result = new HashMap<>();
        List<Map<String, String>> energyList = new ArrayList<>();
        List<String> timeList = new ArrayList<>();
        List<String> monitorIdLists = new ArrayList<>();
        LinkedHashMap<String, List<Float>> monitorInfoMap = new LinkedHashMap<>();
        if (!paramMap.containsKey("type") || !paramMap.containsKey("energyType") ||
                String.valueOf(paramMap.get("startTime")).equals("") || String.valueOf(paramMap.get("endTime")).equals("")) {
            return result;
        }
        String energyType = String.valueOf(paramMap.get("energyType"));
        //小时 天 月 年
        String type = String.valueOf(paramMap.get("type"));
        BaseMonitorInfo monitorInfo = new BaseMonitorInfo();
        List<BaseMonitorInfo> monitorInfoList = baseMonitorInfoService.selectBaseMonitorInfoList(monitorInfo);
        monitorInfo.setMonitorType(Long.parseLong(energyType));
        if (paramMap.containsKey("monitorIds")) {
            String monitorIds = String.valueOf(paramMap.get("monitorIds"));
            if (monitorIds.contains(",")) {
                String[] ids = String.valueOf(paramMap.get("monitorIds")).split(",");
                monitorIdLists.addAll(Arrays.asList(ids));
            } else {
                if (!monitorIds.equals("")) {
                    monitorIdLists.add(monitorIds);
                }
            }
        }

        switch (type) {
            case "month":
                timeList = DateUtils.getSortedMonthList(DateUtils.getDatesBetween(String.valueOf(paramMap.get("startTime")), String.valueOf(paramMap.get("endTime"))), type);
                break;
            case "year":
                timeList = DateUtils.getSortedMonthList(DateUtils.getDatesBetween(String.valueOf(paramMap.get("startTime")), String.valueOf(paramMap.get("endTime"))), type);
                break;
            case "hour":
                timeList = DateUtils.getHourlyIntervals(String.valueOf(paramMap.get("startTime")), String.valueOf(paramMap.get("endTime")));
                break;
            case "day":
                timeList = DateUtils.getDatesBetween(String.valueOf(paramMap.get("startTime")), String.valueOf(paramMap.get("endTime")));
                break;
        }
        List<List<Float>> lists = new ArrayList<>();
        for (String monitorId : monitorIdLists) {
            List<Float> monitorValueList = new ArrayList<>();
            List<String> monitorNameList = monitorInfoList.stream().filter(e -> e.getMonitorId().equals(monitorId))
                    .map(BaseMonitorInfo::getMonitorName).collect(Collectors.toList());

            if (energyType.equals("2")) {
                ReportPointDnb pointDnb = new ReportPointDnb();
                pointDnb.setMonitorId(monitorId);
                pointDnb.setParams(paramMap);
                List<ReportPointDnb> pointDnbList = reportPointDnbMapper.selectReportPointDnbList(pointDnb);
                for (ReportPointDnb reportPointDnb : pointDnbList) {
                    Map<String, String> map = new HashMap<>();
                    map.put("recordTime", DateUtils.parseDateToStr("yyyy-MM-dd HH", reportPointDnb.getBeginTime()));
                    map.put("expend", reportPointDnb.getExpend().toString());
                        energyList.add(map);
                }
            } else if (energyType.equals("3")) {
                ReportPointWater reportPointWater = new ReportPointWater();
                reportPointWater.setMonitorId(monitorId);
                reportPointWater.setParams(paramMap);
                List<ReportPointWater> reportPointWaters = reportPointWaterMapper.selectReportPointWaterList(reportPointWater);
                for (ReportPointWater pointWater : reportPointWaters) {
                    Map<String, String> map = new HashMap<>();
                    map.put("recordTime", DateUtils.parseDateToStr("yyyy-MM-dd HH", pointWater.getBeginTime()));
                    map.put("expend", pointWater.getExpend().toString());
                    energyList.add(map);
                }
            }
            //                List<BaseMonitorInfo> levelAmmeter = getNextLevelAmmeter(monitorInfoList, monitorId);
//                paramMap.put("monitorId", monitorId);
//                    if (levelAmmeter.size() != 0 && energyList.size() == 0) {
//                        List<String> monitorIdList = levelAmmeter.stream().filter(e -> e.getMonitorStatus() != 1)
//                                .map(BaseMonitorInfo::getMonitorId).collect(Collectors.toList());
//                        paramMap.put("monitorIdList", monitorIdList);
//                        energyList = ammeterTreeMapper.energyConsumptionCurveHour(paramMap);
//                    }
            timeList.forEach(date -> {
                float expend = 0.00f;
                for (Map<String, String> map : energyList) {
                    String recordTime = String.valueOf(map.get("recordTime"));
                    if (type.equals("month")) {
                        recordTime = recordTime.substring(0, 7);
                    } else if (type.equals("year")) {
                        recordTime = recordTime.substring(0, 4);
                    } else if (type.equals("hour")) {
                        date = date.substring(0, 13);
                    } else if (type.equals("day")) {
                        recordTime = recordTime.substring(0, 10);
                    }
                    if (date.equals(recordTime)) {
                        expend += Float.parseFloat(String.valueOf(map.get("expend")));
                    }
                }
                BigDecimal decimal = new BigDecimal(Float.toString(expend));
                decimal = decimal.setScale(2, RoundingMode.HALF_UP);
                monitorValueList.add(decimal.floatValue());
            });
            if (monitorNameList.size() != 0) {
                monitorInfoMap.put(monitorNameList.get(0), monitorValueList);
            }
            lists.add(monitorValueList);
        }
        if (lists.size() != 0) {
            List<Float> sumLineList = IntStream.range(0, lists.get(0).size())
                    .mapToObj(i -> lists.stream()
                            .map(list -> list.get(i))
                            .reduce(0f, Float::sum))
                    .map(f -> Math.round(f * 100.0) / 100.0f)
                    .collect(Collectors.toList());
            result.put("sumLineList", sumLineList);
        }
        List<String> monitorNameList = new ArrayList<>();
        for (String monitorName : monitorInfoMap.keySet()) {
            monitorNameList.add(monitorName);
        }
        result.put("monitorNameList", monitorNameList);
        result.put("timeList", timeList);
        result.put("monitorInfoMap", monitorInfoMap);
        return result;
    }


    public List<Float> energyTimeListData(String energyType, String type, String monitorId, String startTime, String endTime) {
        List<Float> monitorValueList = new ArrayList<>();
        List<String> timeList = new ArrayList<>();
        switch (type) {
            case "month":
            case "year":
                timeList = DateUtils.getSortedMonthList(DateUtils.getDatesBetween(startTime, endTime), type);
                break;
            case "hour":
                timeList = DateUtils.getHourlyIntervals(startTime, endTime);
                break;
            case "day":
                timeList = DateUtils.getDatesBetween(startTime, endTime);
                break;
        }
        List<Map<String, String>> energyList = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        if (energyType.equals("2")) {
            ReportPointDnb pointDnb = new ReportPointDnb();
            pointDnb.setMonitorId(monitorId);
            pointDnb.setParams(params);
            List<ReportPointDnb> pointDnbList = reportPointDnbMapper.selectReportPointDnbList(pointDnb);
            for (ReportPointDnb reportPointDnb : pointDnbList) {
                Map<String, String> map = new HashMap<>();
                map.put("recordTime", DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", reportPointDnb.getBeginTime()));
                map.put("expend", reportPointDnb.getExpend().toString());
                energyList.add(map);
            }
        } else if (energyType.equals("3")) {
            ReportPointWater reportPointWater = new ReportPointWater();
            reportPointWater.setMonitorId(monitorId);
            reportPointWater.setParams(params);
            List<ReportPointWater> reportPointWaters = reportPointWaterMapper.selectReportPointWaterList(reportPointWater);
            for (ReportPointWater pointWater : reportPointWaters) {
                Map<String, String> map = new HashMap<>();
                map.put("recordTime", DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", pointWater.getBeginTime()));
                map.put("expend", pointWater.getExpend().toString());
                energyList.add(map);
            }
        }
        timeList.forEach(date -> {
            float expend = 0.00f;
            for (Map<String, String> map : energyList) {
                String recordTime = String.valueOf(map.get("recordTime"));
                switch (type) {
                    case "month":
                        recordTime = recordTime.substring(0, 7);
                        break;
                    case "year":
                        recordTime = recordTime.substring(0, 4);
                        break;
                    case "hour":
                        date = date.substring(0, 13);
                        recordTime = recordTime.substring(0, 13);
                        break;
                    case "day":
                        recordTime = recordTime.substring(0, 10);
                        break;
                }
                if (date.equals(recordTime)) {
                    expend += Float.parseFloat(String.valueOf(map.get("expend")));
                }
            }
            BigDecimal decimal = new BigDecimal(Float.toString(expend));
            decimal = decimal.setScale(2, RoundingMode.HALF_UP);
            monitorValueList.add(decimal.floatValue());
        });
        return monitorValueList;
    }

    /**
     * 同比分析返回数据
     *
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public Map<String, Object> energyYoyAnalysisData(Map paramMap) {
        HashMap<String, Object> result = new HashMap<>();
        if (!paramMap.containsKey("type") || !paramMap.containsKey("energyType") ||
                String.valueOf(paramMap.get("startTime")).equals("") || String.valueOf(paramMap.get("endTime")).equals("")) {
            return result;
        }
        String energyType = String.valueOf(paramMap.get("energyType"));
        //小时 天 月 年
        String type = String.valueOf(paramMap.get("type"));
        String monitorId = String.valueOf(paramMap.get("monitorId"));
        List<Float> nowList = this.energyTimeListData(energyType, type, monitorId, String.valueOf(paramMap.get("startTime")), String.valueOf(paramMap.get("endTime")));
        List<Float> lastList = this.energyTimeListData(energyType, type, monitorId, DateUtils.getLastYearMonthDayTime(String.valueOf(paramMap.get("startTime"))),
                DateUtils.getLastYearMonthDayTime(String.valueOf(paramMap.get("endTime"))));
        result.put("今年", nowList);
        result.put("去年", lastList);
        result.put("timeList", DateUtils.getTimeList(String.valueOf(paramMap.get("startTime")), String.valueOf(paramMap.get("endTime")), type));
        return result;
    }

    /**
     * 线损分析返回数据
     *
     * @param baseLineLoss
     * @return
     */
    @Override
//    //@DS("#header.poolName")
//    public List<Map<String, String>> lineLossAnalysisData(@RequestBody BaseLineLoss baseLineLoss) {
    public List<Map<String, String>> lineLossAnalysisData(BaseLineLoss baseLineLoss) {
        List<Map<String, String>> result = new ArrayList<>();

//todo
//        Long monitorType = baseLineLoss.getMonitorType();
        Long monitorType = 2L;

        if (baseLineLoss.getParams().get("beginCollectTime").equals("") || baseLineLoss.getParams().get("beginCollectTime").equals("endCollectTime")) {
            return result;
        }
        Map<String, Object> baseLineLossParams = baseLineLoss.getParams();
        HashMap<String, Object> params = new HashMap<>();
        baseLineLoss.setParams(params);
        //查询目前线损对象集合
        List<BaseLineLoss> baseLineLosses = baseLineLossMapper.selectBaseLineLossList(baseLineLoss);
        try {
            //查询线路计量信息对象集合
            List<BaseLineMonitor> lineMonitorList = baseLineMonitorMapper.selectBaseLineMonitorList(new BaseLineMonitor());
            for (BaseLineLoss lineLoss : baseLineLosses) {
                HashMap<String, String> hashMap = new HashMap<>();
                List<Map<String, String>> energyConsumptionList = new ArrayList<>();
                hashMap.put("lineLossId", lineLoss.getLineLossId());
                hashMap.put("lineLossName", lineLoss.getLineLossName());
                hashMap.put("monitorType", String.valueOf(monitorType));
                String monitorId = lineLoss.getMonitorId();
                String monitorName = lineLoss.getMonitorName();
                //通过id查询线路计量信息
                BaseLineMonitor monitorInfo = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(monitorId);
//                System.out.println(monitorInfo.getMonitorId()+"=====================================");
                //多路线损
                //用“|”将多路线损的线损对象id分隔开
                List<String> monitorIdMultiwayList = Arrays.asList(monitorId.split("[|]"));
                List<String> monitorNameMultiwayList = Arrays.asList(monitorName.split("[|]"));
                //先将字符串分开，判断该设备是否是多路线损
                if (StringUtils.isNull(monitorInfo) && monitorIdMultiwayList.size() == 1) {
                    continue;
                }
                //再将id拼接起来 存入hashmap
                hashMap.put("monitorId", String.join("|", monitorIdMultiwayList));
                hashMap.put("monitorName", String.join("|", monitorNameMultiwayList));
                HashSet<String> monitorIdSet = new HashSet<>();
//                for (String monitorIdSingle : monitorIdMultiwayList) {
//                        List<BaseLineMonitor> baseMonitorInfos = getLowestLevelLineMonitorList(lineMonitorList, monitorIdSingle);
//                        Set<String> monitorIdList = baseMonitorInfos.stream().map(BaseLineMonitor::getMonitorId).collect(Collectors.toSet());
//                        monitorIdSet.addAll(monitorIdList);
//                    }
                //通过多路线损中的每一个id查询
                for (String monitorIdSingle : monitorIdMultiwayList) {
                    //根据id查询线路计量信息
                    BaseLineMonitor baseLineMonitor = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(monitorIdSingle);
                    BaseLineMonitor lineMonitor = new BaseLineMonitor();
                    //以该id为父级查询子集并存入集合
                    lineMonitor.setParentId(baseLineMonitor.getObjid());
                    List<BaseLineMonitor> baseLineMonitors = baseLineMonitorMapper.selectBaseLineMonitorList(lineMonitor);
                    Set<String> monitorIdList = baseLineMonitors.stream().map(BaseLineMonitor::getMonitorId).collect(Collectors.toSet());
                    //将子集存入monitorIdSet
                    monitorIdSet.addAll(monitorIdList);
                }
                HashMap<String, Object> map = new HashMap<>();
                map.put("monitorIdList", new ArrayList<>(monitorIdSet));
                map.put("startTime", baseLineLossParams.get("beginCollectTime"));
                map.put("endTime", baseLineLossParams.get("endCollectTime"));
                BigDecimal inputUsage = new BigDecimal(0);
                BigDecimal outputUsage = new BigDecimal(0);
                BigDecimal lossUsage = new BigDecimal(0);
                if (monitorType == 2L) {
                    ReportPointDnb pointDnb = new ReportPointDnb();
                    //将多路线损拆分后的id存入整点数据中，通过id查询整点数据在时间内的耗量
                    baseLineLossParams.put("monitorIdList", monitorIdMultiwayList);
                    pointDnb.setParams(baseLineLossParams);
                    List<ReportPointDnb> pointDnbList = reportPointDnbMapper.selectReportPointDnbList(pointDnb);
                    //将查询到的子集耗量加在一起
                    inputUsage = pointDnbList.stream()
                            .map(ReportPointDnb::getExpend)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    hashMap.put("inputUsage", inputUsage.toPlainString());
                    energyConsumptionList = reportPointDnbMapper.energyConsumptionReportByTime(map);

                } else if (monitorType == 3L) {
                    ReportPointWater pointWater = new ReportPointWater();
                    baseLineLossParams.put("monitorIdList", monitorIdMultiwayList);
                    pointWater.setParams(baseLineLossParams);
                    List<ReportPointWater> pointWaters = reportPointWaterMapper.selectReportPointWaterList(pointWater);
                    inputUsage = pointWaters.stream()
                            .map(ReportPointWater::getExpend)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    hashMap.put("inputUsage", inputUsage.toPlainString());
                    energyConsumptionList = reportPointWaterMapper.energyConsumptionReportByTime(map);
                }
                if (energyConsumptionList.size() != 0) {
                    //对父级设备的耗量进行累加
                    outputUsage = energyConsumptionList.stream()
                            .map(m -> String.valueOf(m.get("expend")))
                            .map(BigDecimal::new)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    hashMap.put("outputUsage", outputUsage.toPlainString());
                }else {
                    hashMap.put("outputUsage", "0");
                }
                if (inputUsage.compareTo(outputUsage) > 0){
                    lossUsage = inputUsage.subtract(outputUsage);
                }
                BigDecimal lossRate = divideRate(lossUsage, inputUsage);
                hashMap.put("lossUsage", lossUsage.toPlainString());
                hashMap.put("lossRate", lossRate.toPlainString() + "%");
                result.add(hashMap);
            }
        } catch (Exception e) {
            System.out.println("线损分析返回数据异常:" + e.getMessage());
        }
        return result;
    }

    public static BigDecimal divideRate(BigDecimal dividend, BigDecimal divisor) {
        if (divisor.compareTo(BigDecimal.ZERO) == 0) {
            // 如果除数为0，则返回0
            return BigDecimal.ZERO;
        }
        return dividend.divide(divisor, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
    }


    /**
     * 线损分析详情页面返回数据
     *
     * @param baseLineLoss
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public List<Map<String, String>> lineLossAnalysisDetailsData(BaseLineLoss baseLineLoss) {
        List<Map<String, String>> result = new ArrayList<>();
        String monitorId = baseLineLoss.getMonitorId();
        Long monitorType = baseLineLoss.getMonitorType();
        BaseLineMonitor baseLineM = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(monitorId);
        //查询不到该id且该id不是多路线损设备
        if (StringUtils.isNull(baseLineM) && !monitorId.contains(",")) {
            return result;
        }
        List<Map<String, String>> energyConsumptionList = new ArrayList<>();
        //查询所有的线路设备集合
        List<BaseLineMonitor> lineMonitorList = baseLineMonitorMapper.selectBaseLineMonitorList(new BaseLineMonitor());

        //多路线损
        //将多个设备id用，分开
        List<String> monitorIdMultiwayList = Arrays.asList(monitorId.split(","));
        HashSet<String> monitorIdSet = new HashSet<>();
        //
        for (String monitorIdSingle : monitorIdMultiwayList) {
//            List<BaseLineMonitor> baseMonitorInfos = getLowestLevelLineMonitorList(lineMonitorList, monitorIdSingle);
//            Set<String> monitorIdList = baseMonitorInfos.stream().map(BaseLineMonitor::getMonitorId).collect(Collectors.toSet());
//            monitorIdSet.addAll(monitorIdList);
            //根据id查询设备对象
            BaseLineMonitor baseLineMonitor = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(monitorIdSingle);
            BaseLineMonitor lineMonitor = new BaseLineMonitor();

            lineMonitor.setParentId(baseLineMonitor.getObjid());
            //查询子集
            List<BaseLineMonitor> baseLineMonitors = baseLineMonitorMapper.selectBaseLineMonitorList(lineMonitor);
            //将查询出的子集存入
            Set<String> monitorIdList = baseLineMonitors.stream().map(BaseLineMonitor::getMonitorId).collect(Collectors.toSet());
            monitorIdSet.addAll(monitorIdList);
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("monitorIdList", new ArrayList<>(monitorIdSet));
        map.put("startTime", baseLineLoss.getParams().get("beginCollectTime"));
        map.put("endTime", baseLineLoss.getParams().get("endCollectTime"));
        if (monitorType == 2L) {
            energyConsumptionList = reportPointDnbMapper.energyConsumptionAnalysisDetails(map);
        } else if (monitorType == 3L) {
            energyConsumptionList = reportPointWaterMapper.energyConsumptionAnalysisDetails(map);
        }
        return energyConsumptionList;
    }

    /**
     * 线损分析详情页面图表
     *
     * @param baseLineLoss
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public Map<String, Object> lineLossAnalysisDetailsCharts(BaseLineLoss baseLineLoss) {
        Map<String, Object> result = new HashMap<>();
        String monitorId = baseLineLoss.getMonitorId();
        Long monitorType = baseLineLoss.getMonitorType();
        BaseMonitorInfo monitorInfo = baseMonitorInfoMapper.selectBaseMonitorInfoByMonitorId(monitorId);
        if (StringUtils.isNull(monitorInfo) || StringUtils.isEmpty(String.valueOf(baseLineLoss.getParams().get("beginCollectTime")))
                || StringUtils.isEmpty(String.valueOf(baseLineLoss.getParams().get("endCollectTime")))) {
            return result;
        }
        BaseMonitorInfo baseMonitorInfo = new BaseMonitorInfo();
        List<Map<String, String>> energyConsumptionList = new ArrayList<>();
        baseMonitorInfo.setParentId(monitorInfo.getObjid());
        List<BaseMonitorInfo> baseMonitorInfos = baseMonitorInfoMapper.selectBaseMonitorInfoList(baseMonitorInfo);
        List<String> monitorIdList = baseMonitorInfos.stream().map(BaseMonitorInfo::getMonitorId).collect(Collectors.toList());
        HashMap<String, Object> map = new HashMap<>();
        String beginCollectTime = String.valueOf(baseLineLoss.getParams().get("beginCollectTime"));
        String endCollectTime = String.valueOf(baseLineLoss.getParams().get("endCollectTime"));
        map.put("monitorIdList", monitorIdList);
        map.put("startTime", beginCollectTime);
        map.put("endTime", endCollectTime);
        if (monitorType == 2L) {
            energyConsumptionList = reportPointDnbMapper.energyConsumptionAnalysisDetails(map);
        } else if (monitorType == 3L) {
            energyConsumptionList = reportPointWaterMapper.energyConsumptionAnalysisDetails(map);
        }
        Map<String, BigDecimal> monitorNameMap = energyConsumptionList.stream().collect(Collectors.groupingBy(e -> String.valueOf(e.get("monitorName")),
                Collectors.reducing(BigDecimal.ZERO, x -> new BigDecimal(String.valueOf(x.get("expend"))), BigDecimal::add)));
        ArrayList<HashMap<String, Object>> pieChart = new ArrayList<>();
        for (String monitorName : monitorNameMap.keySet()) {
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("name", monitorName);
            hashMap.put("value", monitorNameMap.get(monitorName));
            pieChart.add(hashMap);
        }
        result.put("pieChart", pieChart);
        List<String> timeList = new ArrayList<>();
        timeList = DateUtils.getDatesBetween(beginCollectTime, endCollectTime);
        List<Float> monitorValueList = new ArrayList<>();
        List<Map<String, String>> finalEnergyConsumptionList = energyConsumptionList;
        timeList.forEach(date -> {
            float expend = 0.00f;
            for (Map<String, String> energy : finalEnergyConsumptionList) {
                date = date.substring(0, 13);
                String recordTime = String.valueOf(energy.get("pointTime"));
                if (date.equals(recordTime)) {
                    expend += Float.parseFloat(String.valueOf(energy.get("expend")));
                }
            }
            BigDecimal decimal = new BigDecimal(Float.toString(expend));
            decimal = decimal.setScale(2, RoundingMode.HALF_UP);
            monitorValueList.add(decimal.floatValue());
        });
        result.put("lineChartDate", timeList);
        result.put("lineChartValue", monitorValueList);
        return result;
    }


    /**
     * 预览看板折线
     *
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public Map<String, Object> previewPolyline(Map paramMap) {
        HashMap<String, Object> result = new HashMap<>();
        if (String.valueOf(paramMap.get("energyType")).equals("")) {
            return result;
        }
        Long energyType = Long.valueOf(String.valueOf(paramMap.get("energyType")));
        Long type;
        Long relationId;
        if (String.valueOf(paramMap.get("type")).equals("")) {
            type = null;
        } else {
            type = Long.valueOf(String.valueOf(paramMap.get("type")));
        }
        if (String.valueOf(paramMap.get("relationId")).equals("")) {
            relationId = null;
        } else {
            relationId = Long.valueOf(String.valueOf(paramMap.get("relationId")));
        }
        String beginCollectTime = String.valueOf(paramMap.get("beginCollectTime"));
        String endCollectTime = String.valueOf(paramMap.get("endCollectTime"));
        HashMap<String, Object> hashMap = this.energyConsumptionList(type, relationId, energyType, beginCollectTime, endCollectTime);
        result.put("energyDateList", hashMap.get("energyDateList"));
        result.put("todayValueList", hashMap.get("energyValueList"));
        result.put("sumEnergyValue", hashMap.get("sumEnergyValue"));
        HashMap<String, Object> yesterdayMap = this.energyConsumptionList(type, relationId, energyType, DateUtils.getYesterday(beginCollectTime), DateUtils.getYesterday(endCollectTime));
        result.put("yesterdayList", yesterdayMap.get("energyValueList"));
        HashMap<String, Object> lastYearMap = this.energyConsumptionList(type, relationId, energyType, DateUtils.getLastYear(beginCollectTime), DateUtils.getLastYear(endCollectTime));
        result.put("lastYearList", lastYearMap.get("energyValueList"));
        return result;
    }

    /**
     * 线损排名
     *
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public Map<String, Object> lineLossRanking(Map paramMap) {
        HashMap<String, Object> result = new HashMap<>();
        ArrayList<String> nameList = new ArrayList<>();
        ArrayList<Float> valueList = new ArrayList<>();
        if (String.valueOf(paramMap.get("energyType")).equals("")) {
            return result;
        }
        Long energyType = Long.valueOf(String.valueOf(paramMap.get("energyType")));
        Long type;
        if (String.valueOf(paramMap.get("type")).equals("")) {
            type = null;
        } else {
            type = Long.valueOf(String.valueOf(paramMap.get("type")));
        }
        String beginCollectTime = String.valueOf(paramMap.get("beginCollectTime"));
        String endCollectTime = String.valueOf(paramMap.get("endCollectTime"));
        BaseLineLoss baseLineLoss = new BaseLineLoss();
        baseLineLoss.setMonitorType(energyType);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("beginCollectTime", beginCollectTime);
        hashMap.put("endCollectTime", endCollectTime);
//        List<String> monitorIdList = monitorIdListByUnitName(type, energyType);
//        List<String> lossMonitorIdList = new ArrayList<>();
        List<BaseLineLoss> baseLineLosses = baseLineLossMapper.selectBaseLineLossList(baseLineLoss);
//        monitorIdList.forEach(monitorId -> {
//            for (BaseLineLoss lineLoss : baseLineLosses) {
//                if (lineLoss.getMonitorId().equals(monitorId)){
//                    lossMonitorIdList.add(monitorId);
//                }
//            }
//        });
        for (BaseLineLoss lineLoss : baseLineLosses) {
            baseLineLoss.setMonitorId(lineLoss.getMonitorId());
            baseLineLoss.setParams(hashMap);
            List<Map<String, String>> maps = this.lineLossAnalysisData(baseLineLoss);
            if (maps.size() > 0) {
                nameList.add(maps.get(0).get("lineLossName"));
                valueList.add(Float.valueOf(maps.get(0).get("lossUsage")));
            }
        }
        sortReportUitls.sortArrayList(nameList, valueList);
        result.put("nameList", nameList);
        result.put("valueList", valueList);
        return result;
    }

    /**
     * 查询能源耗量
     *
     * @param paramMap
     * @return
     */
    public List<Map<String, String>> energyConsumptionByTime(Map paramMap) {
//        paramMap.put("startTime",  paramMap.get("todayStart"));
//        paramMap.put("endTime",  paramMap.get("todayEnd"));
//        paramMap.put("timeSub", 0);
        List<Map<String, String>> energyList = new ArrayList<>();
        String energyType = String.valueOf(paramMap.get("energyType"));
        if (energyType.equals("2")) {
            energyList = reportPointDnbMapper.energyConsumptionReportByTime(paramMap);
        } else if (energyType.equals("3")) {
            energyList = reportPointWaterMapper.energyConsumptionReportByTime(paramMap);
        }
        return energyList;
    }


    /**
     * 能耗统计返回数据
     *
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public List<Map<String, String>> energyStatisticsData(Map paramMap) {
        List<Map<String, String>> energyList = new ArrayList<>();
        String energyType = String.valueOf(paramMap.get("energyType"));
        if (!String.valueOf(paramMap.get("monitorIdList")).equals("")) {
            String[] monitorIdLists = String.valueOf(paramMap.get("monitorIdList")).split(",");
            List<String> list = new ArrayList<>(Arrays.asList(monitorIdLists));
            paramMap.put("monitorIdList", list);
        } else {
            paramMap.remove("monitorIdList");
        }
        try {
            if (energyType.equals("2")) {
                energyList = reportPointDnbMapper.energyStatisticsData(paramMap);
            } else if (energyType.equals("3")) {
                energyList = reportPointWaterMapper.energyStatisticsData(paramMap);
            }
//             Map<String, String> sumMap =  new HashMap<>();
//            if (energyList.size() > 0){
//                sumMap.put("monitorName","合计：");
//                BigDecimal expend = new BigDecimal("0.00");
//                for (Map<String, String> stringStringMap : energyList) {
//                    expend =  expend.add(new BigDecimal(String.valueOf(stringStringMap.get("expend"))));
//                    sumMap.put("timeRange", String.valueOf(stringStringMap.get("timeRange")));
//                }
//                sumMap.put("expend", expend.toPlainString());
//                energyList.add(sumMap);
//            }
        } catch (Exception e) {
            System.out.println("能耗统计返回数据:" + e.getMessage());
        }
        return energyList;
    }

    @Override
    public List<Map<String, String>> lineLossAnalysisDataTimedTasks(BaseLineLoss baseLineLoss) {
        List<Map<String, String>> result = new ArrayList<>();
        Long monitorType = baseLineLoss.getMonitorType();
        if (baseLineLoss.getParams().get("beginCollectTime").equals("") || baseLineLoss.getParams().get("beginCollectTime").equals("endCollectTime")) {
            return result;
        }
        Map<String, Object> baseLineLossParams = baseLineLoss.getParams();
        HashMap<String, Object> params = new HashMap<>();
        baseLineLoss.setParams(params);
        List<BaseLineLoss> baseLineLosses = baseLineLossMapper.selectBaseLineLossList(baseLineLoss);
        try {
            for (BaseLineLoss lineLoss : baseLineLosses) {
                HashMap<String, String> hashMap = new HashMap<>();
                List<Map<String, String>> energyConsumptionList = new ArrayList<>();
                hashMap.put("lineLossId", lineLoss.getLineLossId());
                hashMap.put("lineLossName", lineLoss.getLineLossName());
                hashMap.put("monitorType", String.valueOf(monitorType));
                String monitorId = lineLoss.getMonitorId();
                String monitorName = lineLoss.getMonitorName();
                BaseLineMonitor monitorInfo = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(monitorId);
                //多路线损
                List<String> monitorIdMultiwayList = Arrays.asList(monitorId.split("[|]"));
                List<String> monitorNameMultiwayList = Arrays.asList(monitorName.split("[|]"));
                if (StringUtils.isNull(monitorInfo) && monitorIdMultiwayList.size() == 1) {
                    continue;
                }
                hashMap.put("monitorId", String.join("|", monitorIdMultiwayList));
                hashMap.put("monitorName", String.join("|", monitorNameMultiwayList));
                HashSet<String> monitorIdSet = new HashSet<>();
                for (String monitorIdSingle : monitorIdMultiwayList) {
                    BaseLineMonitor baseLineMonitor = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(monitorIdSingle);
                    BaseLineMonitor lineMonitor = new BaseLineMonitor();
                    lineMonitor.setParentId(baseLineMonitor.getObjid());
                    List<BaseLineMonitor> baseLineMonitors = baseLineMonitorMapper.selectBaseLineMonitorList(lineMonitor);
                    Set<String> monitorIdList = baseLineMonitors.stream().map(BaseLineMonitor::getMonitorId).collect(Collectors.toSet());
                    monitorIdSet.addAll(monitorIdList);
                }
                HashMap<String, Object> map = new HashMap<>();
                map.put("monitorIdList", new ArrayList<>(monitorIdSet));
                map.put("startTime", baseLineLossParams.get("beginCollectTime"));
                map.put("endTime", baseLineLossParams.get("endCollectTime"));
                BigDecimal inputUsage = new BigDecimal(0);
                BigDecimal outputUsage = new BigDecimal(0);
                BigDecimal lossUsage = new BigDecimal(0);
                if (monitorType == 2L) {
                    ReportPointDnb pointDnb = new ReportPointDnb();
                    baseLineLossParams.put("monitorIdList", monitorIdMultiwayList);
                    pointDnb.setParams(baseLineLossParams);
                    List<ReportPointDnb> pointDnbList = reportPointDnbMapper.selectReportPointDnbList(pointDnb);
                    inputUsage = pointDnbList.stream()
                            .map(ReportPointDnb::getExpend)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    hashMap.put("inputUsage", inputUsage.toPlainString());
                    energyConsumptionList = reportPointDnbMapper.energyConsumptionReportByTime(map);

                } else if (monitorType == 3L) {
                    ReportPointWater pointWater = new ReportPointWater();
                    baseLineLossParams.put("monitorIdList", monitorIdMultiwayList);
                    pointWater.setParams(baseLineLossParams);
                    List<ReportPointWater> pointWaters = reportPointWaterMapper.selectReportPointWaterList(pointWater);
                    inputUsage = pointWaters.stream()
                            .map(ReportPointWater::getExpend)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    hashMap.put("inputUsage", inputUsage.toPlainString());
                    energyConsumptionList = reportPointWaterMapper.energyConsumptionReportByTime(map);
                }
                if (energyConsumptionList.size() != 0) {
                    outputUsage = energyConsumptionList.stream()
                            .map(m -> String.valueOf(m.get("expend")))
                            .map(BigDecimal::new)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    hashMap.put("outputUsage", outputUsage.toPlainString());
                }else {
                    hashMap.put("outputUsage", "0");
                }
                if (inputUsage.compareTo(outputUsage) > 0){
                    lossUsage = inputUsage.subtract(outputUsage);
                }
                BigDecimal lossRate = divideRate(lossUsage, inputUsage);
                hashMap.put("lossUsage", lossUsage.toPlainString());
                hashMap.put("lossRate", lossRate.toPlainString());
                result.add(hashMap);
            }
        } catch (Exception e) {
            System.out.println("线损分析返回数据异常:" + e.getMessage());
        }
        return result;
    }

    /**
     * 预览看板线损折线
     *
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public Map<String, Object> previewLineLossLine(Map paramMap) {
        HashMap<String, Object> result = new HashMap<>();
        ArrayList<String> nameList = new ArrayList<>();
        ArrayList<Float> lossValueList = new ArrayList<>();
        ArrayList<Float> childrenValueList = new ArrayList<>();
        if (String.valueOf(paramMap.get("energyType")).equals("")) {
            return result;
        }
        Long energyType = Long.valueOf(String.valueOf(paramMap.get("energyType")));
        Long type;
        Long relationId;
        if (String.valueOf(paramMap.get("type")).equals("")){
            type = null;
        }else {
            type = Long.valueOf(String.valueOf(paramMap.get("type")));
        }
        if (String.valueOf(paramMap.get("relationId")).equals("")){
            relationId = null;
        }else {
            relationId = Long.valueOf(String.valueOf(paramMap.get("relationId")));
        }
        String beginCollectTime = String.valueOf(paramMap.get("beginCollectTime"));
        String endCollectTime = String.valueOf(paramMap.get("endCollectTime"));
        List<String> dateList = DateUtils.getDatesBetween(beginCollectTime, endCollectTime);
        BaseLineLoss baseLineLoss = new BaseLineLoss();
        baseLineLoss.setMonitorType(energyType);
        List<BaseLineLoss> baseLineLosses = baseLineLossMapper.selectBaseLineLossList(baseLineLoss);
        List<String> monitorIdUnitList = monitorIdListByUnitName(type, relationId, energyType);
        //过滤统计单元匹配baseLineLosses
        baseLineLosses = baseLineLosses.stream() .filter(b -> monitorIdUnitList.contains(b.getMonitorId()))
                .collect(Collectors.toList());
        //线损MonitorIdList
        List<String> lossMonitorIdList = baseLineLosses.stream().map(BaseLineLoss::getMonitorId).collect(Collectors.toList());
        //线损子集MonitorIdList
        List<String> childrenMonitorIdList = new ArrayList<>();
        for (BaseLineLoss lineLoss : baseLineLosses) {
            BaseLineMonitor monitorInfo = baseLineMonitorMapper.selectBaseLineMonitorByMonitorId(lineLoss.getMonitorId());
            if (StringUtils.isNull(monitorInfo)) {
                continue;
            }
            List<BaseLineMonitor> lineMonitorList = baseLineMonitorMapper.selectBaseLineMonitorList(new BaseLineMonitor());
            List<BaseLineMonitor> baseMonitorInfos = getLowestLevelLineMonitorList(lineMonitorList, monitorInfo.getMonitorId());
            List<String> monitorIdList = baseMonitorInfos.stream().map(BaseLineMonitor::getMonitorId).collect(Collectors.toList());
            childrenMonitorIdList.addAll(monitorIdList);
        }

        childrenMonitorIdList = childrenMonitorIdList.stream().distinct().collect(Collectors.toList());
        paramMap.put("timeSub", 10);
        paramMap.put("startTime", beginCollectTime);
        paramMap.put("endTime", endCollectTime);
        paramMap.put("monitorIdList", lossMonitorIdList);
        List<Map<String, String>> lossEnergyList = energyConsumptionByTime(paramMap);
        paramMap.put("monitorIdList", childrenMonitorIdList);
        List<Map<String, String>> childrenEnergyList = energyConsumptionByTime(paramMap);
        dateList.forEach(date -> {
            boolean lossFlag = true;
            boolean childrenFlag = true;
            date = date.substring(0, 10);
            for (Map<String, String> map : lossEnergyList) {
                if (date.equals(String.valueOf(map.get("pointTime")))) {
                    lossFlag = false;
                    lossValueList.add(Float.parseFloat(String.valueOf(map.get("expend"))));
                    break;
                }
            }
            if (lossFlag) {
                lossValueList.add(0.00f);
            }
            for (Map<String, String> map : childrenEnergyList) {
                if (date.equals(String.valueOf(map.get("pointTime")))) {
                    childrenFlag = false;
                    childrenValueList.add(Float.parseFloat(String.valueOf(map.get("expend"))));
                    break;
                }
            }
            if (childrenFlag) {
                childrenValueList.add(0.00f);
            }
        });
        List<Float> valueList = IntStream.range(0, lossValueList.size())
                .mapToObj(i -> Math.max(lossValueList.get(i) - childrenValueList.get(i), 0f))
                .map(value -> Float.parseFloat(new DecimalFormat("#.##").format(value)))
                .collect(Collectors.toList());
        result.put("nameList", dateList);
        result.put("valueList", valueList);
        float lossSum = valueList.stream().reduce(0.0f, Float::sum);
        result.put("lossSum", Math.round(lossSum));
        return result;
    }

    /**
     * 根据统计名获取monitorIdList
     *
     * @param type
     * @param energyType
     * @return
     */
    public List<String> monitorIdListByUnitName(Long type, Long relationId, Long energyType) {
        List<String> monitorIdList = new ArrayList<>();
        BaseTypeRelation relation = new BaseTypeRelation();
        //0-建筑  1-业态  2-分项
        relation.setMonitorType(energyType);
        relation.setType(type);
        relation.setRelationId(relationId);
        try {
            List<BaseTypeRelation> baseTypeRelations = baseTypeRelationMapper.selectBaseTypeRelationList(relation);
            monitorIdList = baseTypeRelations.stream().map(BaseTypeRelation::getMonitorId).collect(Collectors.toList());
        } catch (Exception e) {
            System.out.println("根据统计名获取monitorIdList异常：" + e.getMessage());
        }
        return monitorIdList;
    }

    HashMap<String, Object> energyConsumptionList(Long type, Long relationId, Long energyType, String beginCollectTime, String endCollectTime) {
        HashMap<String, Object> result = new HashMap<>();
        List<Map<String, String>> energyList = new ArrayList<>();
        List<String> dateList = new ArrayList<>();
        List<Float> valueList = new ArrayList<>();
        dateList = DateUtils.getDatesBetween(beginCollectTime, endCollectTime);
        HashMap<String, Object> paramMap = new HashMap<>();
        List<String> monitorIdList = monitorIdListByUnitName(type, relationId, energyType);
        paramMap.put("monitorIdList", monitorIdList);
        paramMap.put("timeSub", 10);
        paramMap.put("startDay", beginCollectTime.substring(0, 10));
        paramMap.put("endDay", endCollectTime.substring(0, 10));
        if (energyType == 2) {
            energyList = reportPointDnbMapper.energyConsumptionReportByTime(paramMap);
        } else if (energyType == 3) {
            energyList = reportPointWaterMapper.energyConsumptionReportByTime(paramMap);
        }
        List<Map<String, String>> finalEnergyList = energyList;
        List<String> resDateList = new ArrayList<>();
        AtomicReference<Float> sumEnergy = new AtomicReference<>(0.00f);
        dateList.forEach(date -> {
            boolean flag = true;
            date = date.substring(0, 10);
            resDateList.add(date);
            for (Map<String, String> map : finalEnergyList) {
                if (date.equals(String.valueOf(map.get("pointTime")))) {
                    flag = false;
                    valueList.add(Float.parseFloat(String.valueOf(map.get("expend"))));
                    sumEnergy.updateAndGet(v -> v + Float.parseFloat(String.valueOf(map.get("expend"))));
                    break;
                }
            }
            if (flag) {
                valueList.add(0.00f);
            }
        });
        result.put("energyDateList", resDateList);
        result.put("energyValueList", valueList);
        DecimalFormat decimalFormat = new DecimalFormat("#.##");
        result.put("sumEnergyValue", decimalFormat.format(sumEnergy.get()).toString());
        return result;
    }

    /**
     * 层级导出报表
     * @param paramMap
     * @return
     */
    @Override
//    //@DS("#header.poolName")
    public List<ExportReport> classificationExportReport(Map paramMap) {
        List<Map<String, String>> energyList = new ArrayList<>();
        String energyType = String.valueOf(paramMap.get("energyType"));
        try {
            if (energyType.equals("2")) {
                energyList = reportPointDnbMapper.energyStatisticsData(paramMap);
            } else if (energyType.equals("3")) {
                energyList = reportPointWaterMapper.energyStatisticsData(paramMap);
            }
        } catch (Exception e) {
            System.out.println("层级导出报表异常数据:" + e.getMessage());
        }
        List<ExportReport> exportReportList = baseLineMonitorMapper.selectLevelLineMonitor(Long.parseLong(energyType));
        for (Map<String, String> map : energyList) {
            if (!map.containsKey("grade")){
                continue;
            }
            String timeRange = String.valueOf(map.get("timeRange"));
            String monitorId = String.valueOf(map.get("monitorId"));
            String monitorName = String.valueOf(map.get("monitorName"));
            BigDecimal expend = new BigDecimal(String.valueOf(map.get("expend")));
            int grade = Integer.parseInt(String.valueOf(map.get("grade")));
            generateExportReport(exportReportList, grade, timeRange, monitorId, monitorName, expend);
        }
        return exportReportList;
    }

    private List<ExportReport> generateExportReport(List<ExportReport> exportReportList, int grade, String timeRange, String monitorId, String monitorName, BigDecimal expend) {
        switch (grade){
            case 1:
                for (ExportReport report : exportReportList) {
                    if (monitorId.equals(report.getOneMonitorId())){
                        report.setTimeRange(timeRange);
                        report.setOneExpend(expend);
                    }
                }
                break;
            case 2:
                for (ExportReport report : exportReportList) {
                    if (monitorId.equals(report.getTwoMonitorId())){
                        report.setTwoExpend(expend);
                    }
                }
                break;
            case 3:
                for (ExportReport report : exportReportList) {
                    if (monitorId.equals(report.getThreeMonitorId())){
                        report.setThreeExpend(expend);
                    }
                }
                break;
            case 4:
                for (ExportReport report : exportReportList) {
                    if (monitorId.equals(report.getFourMonitorId())){
                        report.setFourExpend(expend);
                    }
                }
                break;
            case 5:
                for (ExportReport report : exportReportList) {
                    if (monitorId.equals(report.getFiveMonitorId())){
                        report.setFiveExpend(expend);
                    }
                }
                break;
            default:
                break;
        }
        return exportReportList;
    }

}
