package com.njcn.manufactinflux.service.impl;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.StrPool;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.njcn.influx.imapper.*;
import com.njcn.influx.pojo.po.*;
import com.njcn.influx.query.InfluxQueryWrapper;
import com.njcn.influx.utils.InfluxDbUtils;
import com.njcn.manufactinflux.param.JobQueryParam;
import com.njcn.manufactinflux.service.IInfluxManufactService;
import com.njcn.manufactinflux.service.IMonitorService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.ListUtils;
import org.influxdb.dto.QueryResult;
import org.influxdb.impl.InfluxDBResultMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class InfluxManufactServiceImpl implements IInfluxManufactService {


    static InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();

    @Resource
    private IMonitorService monitorService;

    private final DataVMapper dataVMapper;

    private final DataIMapper dataIMapper;

    private final DataInHarmVMapper dataInHarmVMapper;

    private final DataHarmRateVMapper dataHarmRateVMapper;

    private final DataFlickerMapper dataFlickerMapper;

    private final DataPltMapper dataPltMapper;


    @Value("${spring.influx.target.database}")
    private String database;

    @Value("${spring.influx.target.url}")
    private String url;

    @Value("${spring.influx.target.user}")
    private String user;

    @Value("${spring.influx.target.password}")
    private String password;

    /**
     * 思路：
     * 1、指定数据源的。
     * 数据来源：   指定数据源的情况下，每个表查出联合索引的1000条模板数据，比如phasicType+valueType+qualityFlag
     * 后续所有相同的联合索引从模版中随机获取数据赋值
     * 数据录入：   从目标mysql库中查询出所有的需要做处理的监测点id，做业务循环处理
     * <p>
     * 2、未指定数据源。
     * todo... 区别是底层模板数据是提前准备好的
     *
     * @param jobQueryParam 查询参数
     */
    @Override
    public IPage<Object> manufactInfluxData(JobQueryParam jobQueryParam) {
        System.out.println("执行开始当前时间：" + System.currentTimeMillis());
        //查出需要模拟测试监测点id todo...该方法目前默认1分钟一条数据
        List<String> pmsIds = monitorService.queryIdList();
        //样品数据
        List<DataV> dataVList = new ArrayList<>();
        List<DataI> dataIList = new ArrayList<>();
        List<DataInHarmV> dataInHarmVList = new ArrayList<>();
        List<DataHarmRateV> dataHarmRateVList = new ArrayList<>();
        List<DataPlt> dataPltList = new ArrayList<>();
        List<DataFlicker> dataFlickerList = new ArrayList<>();
        if (jobQueryParam.getSourceType() == 0) {
            //从数据源读取influx数据
            List<String> lineList = Arrays.asList("e5807e73521aa58dec3cb1cf74805281"
                    , "a78e16cd28a428b1c1ee3af25880281d", "ff2d9674c1f1ecce7f33a5bf17fc4f2d"
                    , "f7c58f82fd8ba1f307ef5beec4d462be", "b65ef14ed9e25f682840061b1abb464f"
                    , "44ea885554d88eef661c2671f738125a", "1aacf83cd01dfa3581438cbecf06977f"
                    , "23b8eb64453fbb0e23d9ff1e913c5843", "07ee83be55ec8fa8c8af50cb8a6925d6"
                    , "fbd1201ac204b5f40583a53456ed2de1", "692f8201ba6f50a31f1ab99051ed6985"
                    , "b7f94884e69deb54a26414dcb015b88d");
            String startTime = "2023-09-24 00:00:00";
            String endTime = "2023-09-24 02:00:00";
            //准备数据
            InfluxDbUtils influxDbUtils = new InfluxDbUtils(user, password, url, database, "");
            //todo... 目前仅仅是6张表，后续调整成动态的
            //电压
            InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper(DataV.class);
            influxQueryWrapper.between(DataV::getTime, startTime, endTime).regular(DataV::getLineId, lineList);
            QueryResult dataVResult = influxDbUtils.query(influxQueryWrapper.generateSql());
            dataVList = resultMapper.toPOJO(dataVResult, DataV.class);


            //电流
            influxQueryWrapper = new InfluxQueryWrapper(DataI.class);
            influxQueryWrapper.between(DataI::getTime, startTime, endTime).regular(DataI::getLineId, lineList);
            QueryResult dataIResult = influxDbUtils.query(influxQueryWrapper.generateSql());
            dataIList = resultMapper.toPOJO(dataIResult, DataI.class);


            //电压简谐波赋值
            influxQueryWrapper = new InfluxQueryWrapper(DataInHarmV.class);
            influxQueryWrapper.between(DataInHarmV::getTime, startTime, endTime).regular(DataInHarmV::getLineId, lineList);
            QueryResult dataInHarmRateVResult = influxDbUtils.query(influxQueryWrapper.generateSql());
            dataInHarmVList = resultMapper.toPOJO(dataInHarmRateVResult, DataInHarmV.class);

            //谐波电压含有率数据表
            influxQueryWrapper = new InfluxQueryWrapper(DataHarmRateV.class);
            influxQueryWrapper.between(DataHarmRateV::getTime, startTime, endTime).regular(DataHarmRateV::getLineId, lineList);
            QueryResult dataHarmRateVResult = influxDbUtils.query(influxQueryWrapper.generateSql());
            dataHarmRateVList = resultMapper.toPOJO(dataHarmRateVResult, DataHarmRateV.class);

            //长时闪变数据表
            influxQueryWrapper = new InfluxQueryWrapper(DataPlt.class);
            influxQueryWrapper.between(DataPlt::getTime, startTime, endTime).regular(DataPlt::getLineId, lineList);
            QueryResult dataPltResult = influxDbUtils.query(influxQueryWrapper.generateSql());
            dataPltList = resultMapper.toPOJO(dataPltResult, DataPlt.class);

            //电压闪变数据表
            influxQueryWrapper = new InfluxQueryWrapper(DataFlicker.class);
            influxQueryWrapper.between(DataFlicker::getTime, startTime, endTime).regular(DataFlicker::getLineId, lineList);
            QueryResult dataFlickerResult = influxDbUtils.query(influxQueryWrapper.generateSql());
            dataFlickerList = resultMapper.toPOJO(dataFlickerResult, DataFlicker.class);

        }
        //todo...读文件初始化样品数据

        //根据样品数据开始组装需要插入的数据
        Random random = new Random();

        String start = "2024-01-30 00:00:00";
        String end = "2024-01-30 23:59:59";
        LocalDateTime startTime = LocalDateTimeUtil.parse(start, DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime endTime = LocalDateTimeUtil.parse(end, DatePattern.NORM_DATETIME_PATTERN);
        /**
         * 一个监测点一个监测的造数据？
         */
        for (String pmsId : pmsIds) {
            List<DataV> dataVTempList = new ArrayList<>();
            List<DataI> dataITempList = new ArrayList<>();
            List<DataInHarmV> dataInHarmVTempList = new ArrayList<>();
            List<DataHarmRateV> dataHarmRateVTempList = new ArrayList<>();
            List<DataPlt> dataPltTempList = new ArrayList<>();
            List<DataFlicker> dataFlickerTempList = new ArrayList<>();
            while (startTime.isBefore(endTime)) {

                //电压
                Map<String, List<DataV>> stringListMapDataV = dataVList.stream().collect(Collectors.groupingBy(obj -> obj.getPhaseType().concat(StrPool.UNDERLINE).concat(obj.getValueType())));
                for (String string : stringListMapDataV.keySet()) {
                    DataV tempEle = new DataV();
                    List<DataV> dataVS = stringListMapDataV.get(string);
                    int randomIndex = random.nextInt(dataVS.size());
                    // 获取随机索引处的元素
                    DataV randomElement = dataVS.get(randomIndex);
                    BeanUtils.copyProperties(randomElement, tempEle);
                    tempEle.setTime(startTime.atZone(ZoneId.systemDefault()).toInstant());
                    tempEle.setLineId(pmsId);
                    dataVTempList.add(tempEle);
                }

                //电流
                Map<String, List<DataI>> stringListMapDataI = dataIList.stream().collect(Collectors.groupingBy(obj -> obj.getPhaseType().concat(StrPool.UNDERLINE).concat(obj.getValueType())));
                for (String string : stringListMapDataI.keySet()) {
                    DataI tempEle = new DataI();
                    List<DataI> dataIS = stringListMapDataI.get(string);
                    int randomIndex = random.nextInt(dataIS.size());
                    // 获取随机索引处的元素
                    DataI randomElement = dataIS.get(randomIndex);
                    BeanUtils.copyProperties(randomElement, tempEle);
                    tempEle.setTime(startTime.atZone(ZoneId.systemDefault()).toInstant());
                    tempEle.setLineId(pmsId);
                    dataITempList.add(tempEle);
                }

                //电压简谐波赋值
                Map<String, List<DataInHarmV>> stringListMapDataInHarmRateV = dataInHarmVList.stream().collect(Collectors.groupingBy(obj -> obj.getPhaseType().concat(StrPool.UNDERLINE).concat(obj.getValueType())));
                for (String string : stringListMapDataInHarmRateV.keySet()) {
                    DataInHarmV tempEle = new DataInHarmV();
                    List<DataInHarmV> dataInHarmRateVS = stringListMapDataInHarmRateV.get(string);
                    int randomIndex = random.nextInt(dataInHarmRateVS.size());
                    // 获取随机索引处的元素
                    DataInHarmV randomElement = dataInHarmRateVS.get(randomIndex);
                    BeanUtils.copyProperties(randomElement, tempEle);
                    tempEle.setTime(startTime.atZone(ZoneId.systemDefault()).toInstant());
                    tempEle.setLineId(pmsId);
                    dataInHarmVTempList.add(tempEle);
                }

                //谐波电压含有率数据表
                Map<String, List<DataHarmRateV>> stringListMapDataHarmRateV = dataHarmRateVList.stream().collect(Collectors.groupingBy(obj -> obj.getPhaseType().concat(StrPool.UNDERLINE).concat(obj.getValueType())));
                for (String string : stringListMapDataHarmRateV.keySet()) {
                    DataHarmRateV tempEle = new DataHarmRateV();
                    List<DataHarmRateV> DataHarmRateVS = stringListMapDataHarmRateV.get(string);
                    int randomIndex = random.nextInt(DataHarmRateVS.size());
                    // 获取随机索引处的元素
                    DataHarmRateV randomElement = DataHarmRateVS.get(randomIndex);
                    BeanUtils.copyProperties(randomElement, tempEle);
                    tempEle.setTime(startTime.atZone(ZoneId.systemDefault()).toInstant());
                    tempEle.setLineId(pmsId);
                    dataHarmRateVTempList.add(tempEle);
                }

                //长时闪变数据表 2小时一条数据
                Map<String, List<DataPlt>> stringListMapDataPlt = dataPltList.stream().collect(Collectors.groupingBy(DataPlt::getPhaseType));
                if (startTime.getHour() % 2 == 0 && startTime.getMinute() == 0 && startTime.getSecond() == 0) {
                    for (String string : stringListMapDataPlt.keySet()) {
                        DataPlt tempEle = new DataPlt();
                        List<DataPlt> DataPltS = stringListMapDataPlt.get(string);
                        int randomIndex = random.nextInt(DataPltS.size());
                        // 获取随机索引处的元素
                        DataPlt randomElement = DataPltS.get(randomIndex);
                        BeanUtils.copyProperties(randomElement, tempEle);
                        tempEle.setTime(startTime.atZone(ZoneId.systemDefault()).toInstant());
                        tempEle.setLineId(pmsId);
                        dataPltTempList.add(tempEle);
                    }
                }


                //电压闪变数据表 10分钟一条数据
                Map<String, List<DataFlicker>> stringListMapDataFlicker = dataFlickerList.stream().collect(Collectors.groupingBy(DataFlicker::getPhaseType));
                if (startTime.getMinute() % 10 == 0 && startTime.getSecond() == 0) {
                    for (String string : stringListMapDataFlicker.keySet()) {
                        DataFlicker tempEle = new DataFlicker();
                        List<DataFlicker> DataFlickerS = stringListMapDataFlicker.get(string);
                        int randomIndex = random.nextInt(DataFlickerS.size());
                        // 获取随机索引处的元素
                        DataFlicker randomElement = DataFlickerS.get(randomIndex);
                        BeanUtils.copyProperties(randomElement, tempEle);
                        tempEle.setTime(startTime.atZone(ZoneId.systemDefault()).toInstant());
                        tempEle.setLineId(pmsId);
                        dataFlickerTempList.add(tempEle);
                    }
                }

                         startTime = LocalDateTimeUtil.offset(startTime, 1, ChronoUnit.MINUTES);
            }
            //执行批量入库操作
            System.out.println("插入dataV" + dataVTempList.size() + "条");
            List<List<DataV>> partition = ListUtils.partition(dataVTempList, 10000);
            for (List<DataV> sliceList : partition) {
                List<DataV> tempList = new ArrayList<>(sliceList);
                dataVMapper.insertBatch(tempList);
            }

            System.out.println("插入dataI" + dataITempList.size() + "条");
            List<List<DataI>> partition1 = ListUtils.partition(dataITempList, 10000);
            for (List<DataI> sliceList : partition1) {
                List<DataI> tempList = new ArrayList<>(sliceList);
                dataIMapper.insertBatch(tempList);
            }

            System.out.println("插入dataInHarmV" + dataInHarmVTempList.size() + "条");
            List<List<DataInHarmV>> partition2 = ListUtils.partition(dataInHarmVTempList, 10000);
            for (List<DataInHarmV> sliceList : partition2) {
                List<DataInHarmV> tempList = new ArrayList<>(sliceList);
                dataInHarmVMapper.insertBatch(tempList);
            }

            System.out.println("插入dataInHarmV" + dataHarmRateVTempList.size() + "条");
            List<List<DataHarmRateV>> partition3 = ListUtils.partition(dataHarmRateVTempList, 10000);
            for (List<DataHarmRateV> sliceList : partition3) {
                List<DataHarmRateV> tempList = new ArrayList<>(sliceList);
                dataHarmRateVMapper.insertBatch(tempList);
            }


            System.out.println("插入DataPlt" + dataPltTempList.size() + "条");
            dataPltMapper.insertBatch(dataPltTempList);
            System.out.println("插入DataFlicker" + dataFlickerTempList.size() + "条");
            dataFlickerMapper.insertBatch(dataFlickerTempList);
            //将起始时间初始化
            startTime = LocalDateTimeUtil.parse(start, DatePattern.NORM_DATETIME_PATTERN);
            //清空所有表数据
            dataVTempList.clear();
            dataITempList.clear();
            dataInHarmVTempList.clear();
            dataHarmRateVTempList.clear();
            dataPltTempList.clear();
            dataFlickerTempList.clear();
            System.gc();
        }

        System.out.println("执行结束当前时间：" + System.currentTimeMillis());
        return null;
    }

    public static void main(String[] args) {

        LocalDateTime startTime = LocalDateTimeUtil.parse("2024-01-23 15:00:00", DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime endTime = LocalDateTimeUtil.parse("2024-01-23 16:59:59", DatePattern.NORM_DATETIME_PATTERN);

        System.out.println(startTime.getHour() % 2);
        System.out.println(endTime.getHour() % 2);
    }
}
