package com.mvc.service.sthjb;

import com.mvc.entity.TAiread;
import com.mvc.model.StationAccModel;
import com.mvc.model.TAireadModel;
import com.mvc.model.sthjb.UnitWaterDataModel;
import com.mvc.othermodel.sjhjb.SubWaterMeteringModel;
import com.mvc.othermodel.sjhjb.WaterMeteringLogicModel;
import com.mvc.othermodel.sjhjb.WatereFficiencyModel;
import com.mvc.service.copy.TAireadService;
import com.mvc.service.taizhang.StationAccService;
import com.mvc.service.tyrq.TyrqStatisticsService;
import com.mvc.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class SthjbService {
    @Resource
    private StationAccService stationAccService;

    @Resource
    private TAireadService aireadService;

    @Resource
    private UnitWaterDataService unitWaterDataService;

    @Resource
    private TyrqStatisticsService tyrqStatisticsService;

    public List<WaterMeteringLogicModel> findWaterMeteringLogicModel(String unitCode, String startTime, String endTime) {
        List<StationAccModel> accList = stationAccService.findStationAccByUnitCode(unitCode);

        Date dtStart = DateUtil.parseTimeStr(startTime, "yyyy-MM-dd");
        Date dtEnd = DateUtil.parseTimeStr(endTime, "yyyy-MM-dd");
        dtEnd = DateUtil.getOtherDateByCurrentDate(dtEnd, 1);//要包含最后一天需要+1

        Map<String, BigDecimal> usageMap = new HashMap<String, BigDecimal>();
        for (StationAccModel accModel : accList) {
            //此处先假设,每个设备每天都必须有有效读数
            List<TAiread> aireads = aireadService.findAllTaireadByStationCodeAndTime(accModel.getStationCode(), dtStart, dtEnd);
            if (aireads.size() < 2) {
                continue;
            }
            TAiread startAiread = aireads.get(0);
            TAiread endAiread = aireads.get(aireads.size() - 1);

            if (startAiread.getResultValue() == null || endAiread.getResultValue() == null) {
                System.out.println("findWaterMeteringLogicModel：startAiread.getResultValue()==null||endAiread.getResultValue()==null,stationCode=" + accModel.getStationCode());
                continue;
            }

            usageMap.put(accModel.getStationCode(), endAiread.getResultValue().subtract(startAiread.getResultValue()));
        }

        BigDecimal usageSum = BigDecimal.ZERO;
        List<WaterMeteringLogicModel> waterMeteringLogicModels = new ArrayList<>();

        //单位总用水量,直接根据1级总表计算的
        WaterMeteringLogicModel total = WaterMeteringLogicModel.getMockData_Total();
        BigDecimal totalUsage = calcUsage(usageMap, total);

        //2号楼用水
        WaterMeteringLogicModel building2 = WaterMeteringLogicModel.getMockData_Building2();
        usageSum = usageSum.add(calcUsage(usageMap, building2));

        //3号楼用水
        WaterMeteringLogicModel building3 = WaterMeteringLogicModel.getMockData_Building3();
        usageSum = usageSum.add(calcUsage(usageMap, building3));

        //食堂用水
        WaterMeteringLogicModel canteen = WaterMeteringLogicModel.getMockData_Canteen();
        usageSum = usageSum.add(calcUsage(usageMap, canteen));
        canteen.setUsageRatio(canteen.getUsageValue().divide(totalUsage, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
        waterMeteringLogicModels.add(canteen);

        //绿化用水
        WaterMeteringLogicModel green = WaterMeteringLogicModel.getMockData_Green();
        usageSum = usageSum.add(calcUsage(usageMap, green));
        green.setUsageRatio(green.getUsageValue().divide(totalUsage, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
        waterMeteringLogicModels.add(green);

        //冷却塔补水
        WaterMeteringLogicModel coolingTower = WaterMeteringLogicModel.getMockData_CoolingTower();
        usageSum = usageSum.add(calcUsage(usageMap, coolingTower));
        coolingTower.setUsageRatio(coolingTower.getUsageValue().divide(totalUsage, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
        waterMeteringLogicModels.add(coolingTower);

        //空调补水
        WaterMeteringLogicModel airConditioning = WaterMeteringLogicModel.getMockData_AirConditioning();
        usageSum = usageSum.add(calcUsage(usageMap, airConditioning));
        airConditioning.setUsageRatio(airConditioning.getUsageValue().divide(totalUsage, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
        waterMeteringLogicModels.add(airConditioning);

        //热力站软化水
        WaterMeteringLogicModel heatingStation = WaterMeteringLogicModel.getMockData_HeatingStation();
        usageSum = usageSum.add(calcUsage(usageMap, heatingStation));
        heatingStation.setUsageRatio(heatingStation.getUsageValue().divide(totalUsage, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
        waterMeteringLogicModels.add(heatingStation);


        //办公总用水量=单位总水量-食堂用水量-绿化用水量-冷却塔补水量-空调补水量-热力软化水量
        WaterMeteringLogicModel office = new WaterMeteringLogicModel();
        office.setType(1);
        office.setDisplayName("办公用水");
        BigDecimal officeUsage = totalUsage.subtract(canteen.getUsageValue())
                .subtract(green.getUsageValue())
                .subtract(coolingTower.getUsageValue())
                .subtract(airConditioning.getUsageValue())
                .subtract(heatingStation.getUsageValue());
        office.setUsageValue(officeUsage);
        office.setUsageRatio(office.getUsageValue().divide(totalUsage, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
        waterMeteringLogicModels.add(office);


        //1号楼办公用水量=办公用水总量-2号楼办公用水量-3号楼办公用水量
        WaterMeteringLogicModel building1 = WaterMeteringLogicModel.getMockData_Building3();
        building1.setType(2);
        building1.setDisplayName("1号楼");
        BigDecimal building1Usage = officeUsage.subtract(building2.getUsageValue()).subtract(building3.getUsageValue());
        building1.setUsageValue(building1Usage);

        waterMeteringLogicModels.sort((m1, m2) -> m2.getUsageValue().intValue() - m1.getUsageValue().intValue());
        return waterMeteringLogicModels;
    }

    //根据单位单位及时间，获取下辖站点的用量Map
    private Map<String, BigDecimal> getUsageMap(String unitCode, String startTime, String endTime) {
        List<StationAccModel> accList = stationAccService.findStationAccByUnitCode(unitCode);

        Date dtStart = DateUtil.parseTimeStr(startTime, "yyyy-MM-dd");
        Date dtEnd = DateUtil.parseTimeStr(endTime, "yyyy-MM-dd");
        dtEnd = DateUtil.getOtherDateByCurrentDate(dtEnd, 1);//要包括最后一天,需要+1天

        Map<String, BigDecimal> usageMap = new HashMap<>();
        for (StationAccModel accModel : accList) {
            //此处先假设,每个设备每天都必须有有效读数
            List<TAiread> aireads = aireadService.findAllTaireadByStationCodeAndTime(accModel.getStationCode(), dtStart, dtEnd);
            if (aireads.size() < 2) {
                continue;
            }
            TAiread startAiread = aireads.get(0);
            TAiread endAiread = aireads.get(aireads.size() - 1);

            if (startAiread.getResultValue() == null || endAiread.getResultValue() == null) {
                System.out.println("startAiread.getResultValue()==null||endAiread.getResultValue()==null,stationCode=" + accModel.getStationCode());
                continue;
            }

            usageMap.put(accModel.getStationCode(), endAiread.getResultValue().subtract(startAiread.getResultValue()));
        }
        return usageMap;
    }

    //计算用量
    private BigDecimal calcUsage(Map<String, BigDecimal> usageMap, WaterMeteringLogicModel model) {
        BigDecimal usage = BigDecimal.ZERO;
        Map<String, Integer> stationCodeMap = model.getStationCodeMap();
        for (String stationCode : stationCodeMap.keySet()) {
            if (!usageMap.containsKey(stationCode)) {
                continue;
            }

            usage = usage.add(usageMap.get(stationCode).multiply(new BigDecimal(stationCodeMap.get(stationCode))));
        }
        model.setUsageValue(usage);
        return usage;
    }

    /**
     * 计算次级用水计量率
     *
     * @param unitCode
     * @param startTime
     * @param endTime
     * @return
     */
    public SubWaterMeteringModel calcSubWaterMeteringRatio(String unitCode, String startTime, String endTime) {
        Map<String, BigDecimal> usageMap = getUsageMap(unitCode, startTime, endTime);
        WaterMeteringLogicModel total = WaterMeteringLogicModel.getMockData_Total();//一级表
        WaterMeteringLogicModel secondary = WaterMeteringLogicModel.getMockData_SecondaryWaterMeter();//二级表总和

        SubWaterMeteringModel model = new SubWaterMeteringModel();
        BigDecimal totalUsage = calcUsage(usageMap, total);
        BigDecimal secondaryUsage = calcUsage(usageMap, secondary);
        model.setFirstWaterUsage(totalUsage);
        model.setSecondaryWaterUsage(secondaryUsage);

        if (totalUsage.compareTo(BigDecimal.ZERO) > 0) {
            //用水计量-水计量率:2级表用量/一级表用量 * 100% ,指标：次级用水单元水计量率>=95%
            BigDecimal waterMeteringRate = secondaryUsage.divide(totalUsage, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            model.setSubWaterMeteringRatio(waterMeteringRate);
        }
        return model;
    }

    /**
     * 计算用水效率数据
     *
     * @param unitCode
     * @return
     */
    public WatereFficiencyModel calcWatereFficiency(String unitCode) {
        int year = LocalDate.now().getYear();
        UnitWaterDataModel model = unitWaterDataService.findCurrentUnitWaterData(unitCode, year);
        WatereFficiencyModel watereFficiencyModel = new WatereFficiencyModel();
        if (model == null) {
            return watereFficiencyModel;
        }

        BigDecimal planWaterVolume = model.getPlanWaterVolume();//年计划量
        BigDecimal annualStartWater = model.getAnnualStartWater();//年起始累计量
        watereFficiencyModel.setPlanWaterVolume(planWaterVolume);
        watereFficiencyModel.setAnnualStartWater(annualStartWater);
        watereFficiencyModel.setStaffCount(model.getStaffCount());//在编人数
        watereFficiencyModel.setTempStaffCount(model.getTempStaffCount());//编外人数
        watereFficiencyModel.setTotalCount(model.getStaffCount() + model.getTempStaffCount());//总计人数

        //获取总表的stationCode
        WaterMeteringLogicModel total = WaterMeteringLogicModel.getMockData_Total();
        String stationCode = total.getStationCodeMap().keySet().iterator().next();

        //最新的数据
        TAireadModel aireadModel = aireadService.findLatesTAireadByStationCode(stationCode);

        BigDecimal currentAccumulate = aireadModel.getResultValue();//当前累计量
        watereFficiencyModel.setCurrentAccumulate(currentAccumulate);

        BigDecimal currentUsage = currentAccumulate.subtract(annualStartWater);//当年用量
        watereFficiencyModel.setCurrentUsage(currentUsage);

        BigDecimal waterUsagePerPerson = currentUsage.divide(new BigDecimal(watereFficiencyModel.getTotalCount()), 2, RoundingMode.HALF_UP);
        watereFficiencyModel.setWaterUsagePerPerson(waterUsagePerPerson);//人均用水量

        //当年用量占比
        BigDecimal annualUsageRatio = currentUsage.divide(planWaterVolume, 4, RoundingMode.HALF_UP);
        watereFficiencyModel.setAnnualUsageRatio(annualUsageRatio.setScale(2, RoundingMode.HALF_UP));

        //当前季度
        int month = LocalDate.now().getMonthValue();

        int quarter = month % 3 == 0 ? month / 3 : month / 3 + 1;
        watereFficiencyModel.setCurrentQuarter(quarter);

        //当前季度计划量(每季度25%计算)
        BigDecimal quarterPlanWaterVolume = planWaterVolume.divide(new BigDecimal(4), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(quarter));
        watereFficiencyModel.setQuarterplanWaterVolume(quarterPlanWaterVolume);

        //季度计划量占比
        BigDecimal quarterPlanWaterVolumeRatio = currentUsage.divide(quarterPlanWaterVolume, 4, RoundingMode.HALF_UP);
        watereFficiencyModel.setQuarterUsageRatio(quarterPlanWaterVolumeRatio.setScale(2, RoundingMode.HALF_UP));

        if (annualUsageRatio.compareTo(quarterPlanWaterVolumeRatio) > 0) {
            System.out.println("用量超额");
        }

        Date sampleTime = aireadModel.getSampleTime();//最新数据的采样时间
        LocalDate localDate = DateUtil.dateToLocalDate(sampleTime);

        //采样时间的所属年
        LocalDate firstDayOfYear = localDate.with(TemporalAdjusters.firstDayOfYear());
        Date firstDayOfYearAsDate = Date.from(firstDayOfYear.atStartOfDay(ZoneId.systemDefault()).toInstant());
        //采样年首日到采样时间之间有多少天
        int betweenDays = (int) DateUtil.daysBetween(firstDayOfYearAsDate, sampleTime);
        //日均用水量
        BigDecimal averangeUsage = currentUsage.divide(new BigDecimal(betweenDays), 2, RoundingMode.HALF_UP);
        //预估年用水量
        BigDecimal yearWaterVolume = averangeUsage.multiply(new BigDecimal(365));
        watereFficiencyModel.setAnnualWaterConsumption(yearWaterVolume);

        return watereFficiencyModel;
    }

    /**
     * 计算中央空调补水率
     *
     * @param unitCode
     * @param startTime
     * @param endTime
     * @return
     */
    public SubWaterMeteringModel calcCoolingTowerMakeup(String unitCode, String startTime, String endTime) {
        Date dtStart = DateUtil.parseTimeStr(startTime, "yyyy-MM-dd");
        Date dtEnd = DateUtil.parseTimeStr(endTime, "yyyy-MM-dd");
        dtEnd = DateUtil.getOtherDateByCurrentDate(dtEnd, 1);

        int year = LocalDate.now().getYear();
        //获取当年单位基本数据
        UnitWaterDataModel unitWaterDataModel = unitWaterDataService.findCurrentUnitWaterData(unitCode, year);

        //**注意,此处借用了次级用水计量的对象(前端会转换为map的)
        SubWaterMeteringModel resModel = new SubWaterMeteringModel();
        if (unitWaterDataModel == null || unitWaterDataModel.getCoolingTowerCycle() == null) {
            return resModel;
        }

        BigDecimal coolingTowerCycle = unitWaterDataModel.getCoolingTowerCycle();//冷却塔循环量

        WaterMeteringLogicModel coolingTower = WaterMeteringLogicModel.getMockData_CoolingTower();
        String stationCode = coolingTower.getStationCodeMap().keySet().iterator().next();
        List<TAiread> aireads = aireadService.findAllTaireadByStationCodeAndTime(stationCode, dtStart, dtEnd);

        //此处假设了都是0点的数据(后面要考虑此问题)
        TAiread startAiread = aireads.get(0);
        TAiread endAiread = aireads.get(aireads.size() - 1);
        BigDecimal useage = endAiread.getResultValue().subtract(startAiread.getResultValue());
        long days = DateUtil.daysBetween(dtStart, dtEnd);//相隔天数

        //算出日用水量
        BigDecimal dailyUsage = useage.divide(new BigDecimal(days), 2, RoundingMode.HALF_UP);

        resModel.setFirstWaterUsage(dailyUsage);
        resModel.setSecondaryWaterUsage(coolingTowerCycle);

        BigDecimal rate = dailyUsage.divide(coolingTowerCycle, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
        resModel.setSubWaterMeteringRatio(rate);

        return resModel;
    }

    public Map<String, Object> getRecentUsageData(String unitCode, int days) {
        //获取总表的stationCode
        WaterMeteringLogicModel total = WaterMeteringLogicModel.getMockData_Total();
        String stationCode = total.getStationCodeMap().keySet().iterator().next();
        return getRecentUsageDataByStationCode(stationCode, days);
    }


    /**
     * 获取最近用量数据
     *
     * @param stationCode 站码
     * @param days        天数
     * @return
     */
    public Map<String, Object> getRecentUsageDataByStationCode(String stationCode, int days) {
        days = days < 10 || days > 31 ? 30 : days;//天数限制

        List<String> recentUsageXAxis = new ArrayList<>();//最近用量-X轴名称
        List<BigDecimal> recentUsageYAxis = new ArrayList<>();//最近用量-Y轴数据

        Date today = DateUtil.getZeroTimeOfDay(new Date());
        Date startDate = DateUtil.getOtherDateByCurrentDate(today, -days);
        return getRecentUsageDataByStationCodeAndTime(stationCode, startDate, today);


    }

    /**
     * 获取最近用量数据
     *
     * @param stationCode 站码
     * @param startDate   开始时间
     * @param endDate     结束时间
     * @return
     */
    public Map<String, Object> getRecentUsageDataByStationCodeAndTime(String stationCode, Date startDate, Date endDate) {
        List<String> recentUsageXAxis = new ArrayList<>();//最近用量-X轴名称
        List<BigDecimal> recentUsageYAxis = new ArrayList<>();//最近用量-Y轴数据

        //算用量要+1天,才能包含昨天
        endDate = DateUtil.getOtherDateByCurrentDate(endDate, 1);
        List<TAiread> aireadModels = tyrqStatisticsService.getAireadData(stationCode, startDate, endDate);

        Date tempDate = startDate;//循环变量
        while (tempDate.compareTo(endDate) < 0) {
            Date finalTempDate0 = tempDate;

            tempDate = DateUtil.getOtherDateByCurrentDate(tempDate, 1);

            Optional<TAiread> optional0 = aireadModels.stream().filter(s -> s.getSampleTime().compareTo(finalTempDate0) >= 0).findFirst();
            if (optional0.isPresent()) {
                if (DateUtil.getMinsbetweenTime(finalTempDate0, optional0.get().getSampleTime()) > 60) {
                    //有数据但不是0点范围内 2024-04-07 guozhao
                    //recentUsageYAxis.add(BigDecimal.ZERO);
                    continue;
                }
            } else {
                //没有当天数据
                //recentUsageYAxis.add(BigDecimal.ZERO);
                continue;
            }
            //没有第二天数据
            Date finalTempDate1 = tempDate;
            Optional<TAiread> optional1 = aireadModels.stream().filter(s -> s.getSampleTime().compareTo(finalTempDate1) >= 0).findFirst();
            if (optional1.isPresent()) {
                if (DateUtil.getMinsbetweenTime(finalTempDate1, optional1.get().getSampleTime()) > 60) {
                    //有数据但不是0点范围内 2024-04-07 guozhao
                    //recentUsageYAxis.add(BigDecimal.ZERO);
                    continue;
                }
            } else {
                //没有这一天的起始时间,用量设置为0
                //recentUsageYAxis.add(BigDecimal.ZERO);
                continue;
            }
            recentUsageXAxis.add(DateUtil.formateDate(finalTempDate0, "MM/dd"));
            recentUsageYAxis.add(optional1.get().getResultValue().subtract(optional0.get().getResultValue()));
        }

        Map<String, Object> resMap = new HashMap<>();
        resMap.put("xAxis", recentUsageXAxis);
        resMap.put("yAxis", recentUsageYAxis);
        return resMap;
    }

    /**
     * 根据站码年月获取用量数据
     *
     * @param stationCode
     * @param year
     * @param month
     * @return
     */
    public Map<String, Object> getUsageDataByStationCodeAndYMonth(String stationCode, int year, int month) {
        Date startDate = DateUtil.parseTimeStr(year + "-" + month + "-01", "yyyy-MM-dd");//当月第一天
        Date endDate = DateUtil.getLastDayOfMonth(startDate);

        return getRecentUsageDataByStationCodeAndTime(stationCode, startDate, endDate);
    }

    /**
     * 根据单位代码和年月获取用量
     *
     * @param stationCode
     * @param year
     * @return
     */
    public Map<String, Object> getAnnualUsageDataByStationCodeAndYear(String stationCode, int year) {
        Date startDate = DateUtil.parseTimeStr(year + "-01-01", "yyyy-MM-dd");
        Date endDate = DateUtil.parseTimeStr((year + 1) + "-01-01", "yyyy-MM-dd");

        // 获取整年所有数据
        List<TAiread> aireadModels = tyrqStatisticsService.getAireadData(stationCode, startDate, endDate);

        // 建立时间精确匹配的Map（方便直接取 1号0点 数据）
        Map<Long, TAiread> timeMap = aireadModels.stream()
                .filter(s -> s.getResultValue() != null)
                .collect(Collectors.toMap(
                        s -> s.getSampleTime().getTime(),
                        s -> s,
                        (a, b) -> a // 如果有重复时间取第一个
                ));

        List<String> xAxis = new ArrayList<>();
        List<BigDecimal> yAxis = new ArrayList<>();

        Date tempDate = startDate;

        for (int month = 1; month <= 12; month++) {
            xAxis.add(StringUtils.leftPad(String.valueOf(month), 2, "0"));

            Date monthStart = tempDate;
            Date nextMonthStart = DateUtil.getOtherDateByMonth(monthStart, 1);
            tempDate = nextMonthStart; // 为下轮准备

            TAiread startAiread = timeMap.get(monthStart.getTime());
            TAiread endAiread = timeMap.get(nextMonthStart.getTime());

            if (startAiread != null && endAiread != null) {
                yAxis.add(endAiread.getResultValue().subtract(startAiread.getResultValue()));
            } else {
                // 缺数处理
                yAxis.add(BigDecimal.ZERO);
            }
        }

        Map<String, Object> resMap = new HashMap<>();
        resMap.put("xAxis", xAxis);
        resMap.put("yAxis", yAxis);
        return resMap;
    }

}
