package com.njcn.device.pq.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.device.line.service.LineService;
import com.njcn.device.pq.mapper.RStatOnlinerateDMapper;
import com.njcn.device.pq.pojo.param.OnlineRateParam;
import com.njcn.device.pq.pojo.param.PulicTimeParam;
import com.njcn.device.pq.pojo.param.PulicTimeStatisParam;
import com.njcn.device.pq.pojo.po.RStatOnlinerateD;
import com.njcn.device.pq.pojo.vo.*;
import com.njcn.device.pq.service.CommunicateService;
import com.njcn.device.rstatintegrity.mapper.RStatIntegrityDMapper;
import com.njcn.web.enums.DateFlagEnum;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author denghuajun
 * @date 2022/2/28
 */
@Service
@AllArgsConstructor
public class CommunicateServiceImpl implements CommunicateService {

    final float DEFAULT_ONLINE_RATE = 3.14159f;

    private final LineService lineService;

    private final RStatOnlinerateDMapper onlinerateDMapper;

    private final RStatIntegrityDMapper integrityDMapper;

    @Override
    public CommunicateVO getComFlagInfoData(PulicTimeParam pulicTimeParam) {
        //根据监测点id获取终端状态信息
        return lineService.getComFlagInfoData(pulicTimeParam.getId(), pulicTimeParam.getSearchBeginTime(), pulicTimeParam.getSearchEndTime());
    }

    @Override
    public CommunicateStatisticsVO getRunInfoData(PulicTimeStatisParam pulicTimeStatisParam) {
        CommunicateStatisticsVO communicateStatisticsVO = new CommunicateStatisticsVO();
        //根据监测点id获取终端id
        String devId = lineService.getLineIdByDevId(pulicTimeStatisParam.getId());
        List<Float> floatList = new ArrayList<>();
        List<Float> floats = new ArrayList<>();
        floatList.add(getCondition(pulicTimeStatisParam.getId(), pulicTimeStatisParam.getSearchBeginTime(), pulicTimeStatisParam.getSearchEndTime(), 0));
        floats.add(getCondition(devId, pulicTimeStatisParam.getSearchBeginTime(), pulicTimeStatisParam.getSearchEndTime(), 1));
        if (StringUtils.isNotBlank(pulicTimeStatisParam.getPeriodBeginTime()) && StringUtils.isNotBlank(pulicTimeStatisParam.getPeriodEndTime())) {
            floatList.add(getCondition(pulicTimeStatisParam.getId(), pulicTimeStatisParam.getPeriodBeginTime(), pulicTimeStatisParam.getPeriodEndTime(), 0));
            floats.add(getCondition(devId, pulicTimeStatisParam.getPeriodBeginTime(), pulicTimeStatisParam.getPeriodEndTime(), 1));
        }
        communicateStatisticsVO.setOnlineRateData(floats);
        communicateStatisticsVO.setIntegrityData(floatList);
        return communicateStatisticsVO;
    }

    @Override
    public List<DeviceOnlineDataVO> getRunOnlineRateData(PulicTimeParam pulicTimeParam) {
        List<DeviceOnlineDataVO> deviceOnlineDataList = new ArrayList<>();
        String devId = lineService.getLineIdByDevId(pulicTimeParam.getId());

        LambdaQueryWrapper<RStatOnlinerateD> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(RStatOnlinerateD::getDevIndex, devId)
                .between(RStatOnlinerateD::getTimeId, pulicTimeParam.getSearchBeginTime(), pulicTimeParam.getSearchEndTime());
        List<RStatOnlinerateD> rStatOnlinerateDList = onlinerateDMapper.selectList(lambdaQueryWrapper);


        List<String> intervalTime = processDateRange(pulicTimeParam.getSearchBeginTime(), pulicTimeParam.getSearchEndTime(),pulicTimeParam.getTimeFlag());

        if (isMonthlyTimeFlag(pulicTimeParam.getTimeFlag())) {
            // 按月处理
            Map<String, List<RStatOnlinerateD>> map = rStatOnlinerateDList.stream().collect(Collectors.groupingBy(it -> it.getTimeId().format(DateTimeFormatter.ofPattern(DatePattern.NORM_MONTH_PATTERN))));
            for (String interTime : intervalTime) {
                DeviceOnlineDataVO deviceOnlineDataVO = new DeviceOnlineDataVO();
                deviceOnlineDataVO.setDateView(interTime);
                if (map.containsKey(interTime)) {
                    double rate = map.get(interTime).stream().mapToDouble(it -> (double) it.getOnlineMin() / (it.getOnlineMin() + it.getOfflineMin())).average().orElse(3.14159);
                    deviceOnlineDataVO.setOnlineRate(rate == DEFAULT_ONLINE_RATE ? DEFAULT_ONLINE_RATE : new BigDecimal(rate * 100).setScale(2, RoundingMode.HALF_UP).floatValue());
                }else {
                    deviceOnlineDataVO.setOnlineRate(DEFAULT_ONLINE_RATE);
                }
                deviceOnlineDataList.add(deviceOnlineDataVO);
            }
        } else {
            // 按日处理
            Map<String, List<RStatOnlinerateD>> map = rStatOnlinerateDList.stream().collect(Collectors.groupingBy(it -> it.getTimeId().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN))));
            for (String interTime : intervalTime) {
                DeviceOnlineDataVO deviceOnlineDataVO = new DeviceOnlineDataVO();
                deviceOnlineDataVO.setDateView(interTime);
                if (map.containsKey(interTime)) {
                    double rate = map.get(interTime).stream().mapToDouble(it -> (double) it.getOnlineMin() / (it.getOnlineMin() + it.getOfflineMin())).average().orElse(3.14159);
                    deviceOnlineDataVO.setOnlineRate(rate == DEFAULT_ONLINE_RATE ? DEFAULT_ONLINE_RATE : new BigDecimal(rate * 100).setScale(2, RoundingMode.HALF_UP).floatValue());
                }else {
                    deviceOnlineDataVO.setOnlineRate(DEFAULT_ONLINE_RATE);
                }
                deviceOnlineDataList.add(deviceOnlineDataVO);
            }
        }
        return deviceOnlineDataList;
    }

    // 判断是否为按月/季/年统计
    private boolean isMonthlyTimeFlag(int timeFlag) {
        return timeFlag == 1 || timeFlag == 2;
    }



    /**
     * influxDB相关操作
     * 查询监测点的数据完整性
     */
    private Float getCondition(String lineList, String startTime, String endTime, Integer state) {
        final Float[] resultList = {0.0f};
        OnlineRateParam param = new OnlineRateParam();
        param.setIds(Arrays.asList(lineList));
        param.setStartTime(DateUtil.beginOfDay(DateUtil.parse(startTime)).toString());
        param.setEndTime(DateUtil.endOfDay(DateUtil.parse(endTime)).toString());
        if (state == 1) {
            //在线率
            List<RStatOnlineRateVO> onlineRateByDevIds = onlinerateDMapper.getOnlineRateByDevIds(param);
            if (CollUtil.isNotEmpty(onlineRateByDevIds)) {
                onlineRateByDevIds.forEach(po -> {
                    //数据完整性 保留四位小数
                    resultList[0] = po.getOnlineRate() == null ? null : BigDecimal.valueOf(Float.parseFloat(po.getOnlineRate().toString())).setScale(4, BigDecimal.ROUND_HALF_UP).floatValue();
                });
            }
        } else {
            //数据完整率
            List<RStatIntegrityVO> onIntegrityByIds = integrityDMapper.getOnIntegrityByIds(param);
            if (CollUtil.isNotEmpty(onIntegrityByIds)) {
                onIntegrityByIds.forEach(po -> {
                    //数据完整性 保留四位小数
                    resultList[0] = po.getIntegrityRate() == null ? null : BigDecimal.valueOf(Float.parseFloat(po.getIntegrityRate().toString())).setScale(4, BigDecimal.ROUND_HALF_UP).floatValue();
                });
            }
        }
        return resultList[0];
    }




    public static List<String> processDateRange(String startDateStr, String endDateStr, Integer timeType) {
        DateTime startDate = DateUtil.parse(startDateStr, DatePattern.NORM_DATE_PATTERN);
        DateTime endDate = DateUtil.parse(endDateStr, DatePattern.NORM_DATE_PATTERN);

        List<String> result = new ArrayList<>();

        // 计算月份差（基于每月1号计算）
        DateTime startMonth = DateUtil.beginOfMonth(startDate);
        DateTime endMonth = DateUtil.beginOfMonth(endDate);
        long monthsBetween = DateUtil.betweenMonth(startMonth, endMonth, false);

        if (Objects.equals(timeType, DateFlagEnum.WEEK_FLAG.getCode()) ||Objects.equals(timeType, DateFlagEnum.CUSTOM_FLAG.getCode()) ||Objects.equals(timeType, DateFlagEnum.MONTH_FLAG.getCode())) {
            // 同一个月，返回每天日期
            DateRange dailyRange = new DateRange(startDate, endDate, DateField.DAY_OF_MONTH);
            dailyRange.forEach(date -> result.add(DateUtil.format(date, DatePattern.NORM_DATE_PATTERN)));
        } else {
            // 大于一个季度，返回每月第一天日期
            DateTime current = DateUtil.beginOfMonth(startDate);
            while (current.isBeforeOrEquals(endDate)) {
                result.add(DateUtil.format(current, DatePattern.NORM_MONTH_PATTERN));
                current = DateUtil.offsetMonth(current, 1);
            }
        }
        return result;
    }


}
