package com.njcn.energy.controller;


import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.njcn.energy.pojo.api.EleIntegrityFeignClient;
import com.njcn.energy.pojo.api.EleOnlineRateFeignClient;
import com.njcn.energy.pojo.dto.HarmonicDTO;
import com.njcn.energy.pojo.dto.OnlineRateDTO;
import com.njcn.influx.config.InfluxDbConfig;
import com.njcn.influx.utils.InfluxDbUtils;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.influxdb.InfluxDB;
import org.influxdb.dto.BatchPoints;
import org.influxdb.dto.Point;
import org.influxdb.dto.QueryResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RestController
@Api(tags = "用能系统数据调度")
@RequiredArgsConstructor
@Slf4j
@RequestMapping("energyJob")
public class StatisticDataRunController {

    private final Integer POWER_DATA_DUE = 96;

    private final Integer AIR_DATA_DUE = 288;

    private final InfluxDbUtils influxDbUtils;

    private final InfluxDbConfig influxDbConfig;

    private final EleOnlineRateFeignClient eleOnlineRateFeignClient;

    private final EleIntegrityFeignClient eleIntegrityFeignClient;


    /**
     * 调度统计电量增量
     */
    @GetMapping("electricCalJob")
    public void electricCalJob() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar startTime = Calendar.getInstance();

        startTime.add(Calendar.MINUTE, -40);
        String start = sdf.format(startTime.getTime());

        Calendar endTime = Calendar.getInstance();
        //endTime.add(Calendar.DAY_OF_MONTH,-8);
        String end = sdf.format(endTime.getTime());

        String sql = "select * from power_data where time > '" + start + "' and time < '" + end + "' order by time";
        List<Map<String, Object>> list = influxDbUtils.getResult(sql);

        if (CollectionUtil.isNotEmpty(list)) {
            Map lineTemMap = new HashMap<>();
            List<Map<String, Object>> insertObj = new ArrayList<>();
            list.stream().collect(Collectors.groupingBy((item) -> item.get("LineId"), Collectors.toList())).forEach(lineTemMap::put);
            lineTemMap.forEach((lineId, mapList) -> {
                List<Map<String, Object>> tmpList = (List) mapList;
                if (CollectionUtil.isNotEmpty(tmpList)) {
                    for (int i = 0; i < tmpList.size(); i++) {
                        if (i != 0) {
                            Map<String, Object> mapEnd = tmpList.get(i);
                            Map<String, Object> mapStart = tmpList.get(i - 1);
                            Long endT = (Long) mapEnd.get("time") + 28800;
                            Long startT = (Long) mapStart.get("time") + 28800;
                            if (endT > startT) {
                                Map<String, Object> map = new HashMap<>();
                                if (endT - startT == 60 * 15) {
                                    for (Map.Entry<String, Object> entry : tmpList.get(i).entrySet()) {
                                        if (entry.getKey().equals("Phase") || entry.getKey().equals("LineId") || entry.getKey().equals("Stat_Method")) {
                                            map.put(entry.getKey(), entry.getValue());
                                        } else if (entry.getKey().equals("time")) {
                                            map.put(entry.getKey(), endT);
                                        } else {
                                            //定义 float最大值
                                            Float endThis = Float.parseFloat(entry.getValue().toString());
                                            Float startThis = Float.parseFloat(mapStart.get(entry.getKey()).toString());
                                            if (-1000000f == endThis || -1000000f == startThis) {
                                                map.put(entry.getKey(), -1000000f);
                                            } else {
                                                map.put(entry.getKey(), endThis - startThis);
                                            }
                                        }
                                    }
                                    insertObj.add(map);
                                } else {
                                    //缺少数据处理

                                }
                            } else {
                                log.error("时间起始顺序错误！");
                            }
                        }
                    }
                }
            });

            if (CollectionUtil.isNotEmpty(insertObj)) {
                BatchPoints batchPoints = BatchPoints.database(influxDbConfig.getDatabase()).build();
                for (Map<String, Object> it : insertObj) {
                    Point.Builder point = Point.measurement("power_data_add");
                    it.forEach((key, val) -> {
                        if (key.equals("LineId")) {
                            point.tag(key, val.toString());
                        } else if (key.equals("time")) {
                            point.time((Long) val, TimeUnit.SECONDS);
                        } else if (key.equals("Phase") || key.equals("Stat_Method")) {
                            point.addField(key, val.toString());
                        } else {
                            point.addField(key, (Float) val);
                        }
                    });
                    Point p = point.build();
                    batchPoints.point(p);
                }

                try {
                    influxDbUtils.batchInsert(batchPoints, TimeUnit.SECONDS);
                    HashMap<String, Map<String, Object>> hashMap = new HashMap<>();
                    for (int j = 0; j < insertObj.size(); j++) {
                        hashMap.put(insertObj.get(j).get("LineId").toString(), insertObj.get(j));
                    }
                    hashMap.forEach((key, val) -> {
                        Long t = (Long) val.get("time") * 1000;
                        String tt = Instant.ofEpochMilli((Long) val.get("time") * 1000).toString();
                        String sqlQs = "delete from power_data_add_Real where time< '" + tt + "' and LineId ='" + key + "'";
                        influxDbUtils.deleteMeasurementData(sqlQs);
                        Map<String, Object> filedss = new HashMap<>();
                        Map<String, String> tagss = new HashMap<>();
                        val.forEach((keytem, valtem) -> {
                            if (keytem.equals("time")) {

                            } else if (keytem.equals("LineId")) {
                                tagss.put(keytem, valtem.toString());
                            } else {
                                filedss.put(keytem, valtem);
                            }
                        });
                        influxDbUtils.insert("power_data_add_Real", tagss, filedss, t, TimeUnit.MILLISECONDS);
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            log.error(start + "——————" + end + "influxdb数据库power_data表数据为空,请联系管理员排查");
        }


    }


    /**
     * 用能终端在线率数据
     * -------------------------------------------------start-----------------------------------------------------------
     */
    @GetMapping("eleOnlineRateJob")
    public void eleOnlineRateJobHandler() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)-1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.set(calendar2.get(Calendar.YEAR), calendar2.get(Calendar.MONTH), calendar2.get(Calendar.DAY_OF_MONTH)-1, 23, 59, 59);
        calendar2.set(Calendar.MILLISECOND, 0);
        String startTime = format.format(calendar.getTime());
        String endTime = format.format(calendar2.getTime());
        List<OnlineRateDTO> list = eleOnlineRateFeignClient.getDeviceTime(startTime,endTime).getData();
        createOnlineMeasurement(list,calendar.getTimeInMillis());
    }

    /**
     * 生成用能终端在线率表
     */
    private void createOnlineMeasurement(List<OnlineRateDTO> list, long time){
        List<String> records = new ArrayList<String>();
        list.forEach(item->{
            Map<String, String> tags = new HashMap<>();
            Map<String, Object> fields = new HashMap<>();
            tags.put("device_id",item.getDeviceId());
            fields.put("online_rate",item.getOnlineRate());
            Point point = influxDbUtils.pointBuilder("ele_online_rate", time, TimeUnit.MILLISECONDS, tags, fields);
            BatchPoints batchPoints = BatchPoints.database(influxDbConfig.getDatabase()).tag("device_id", item.getDeviceId()).retentionPolicy("").consistency(InfluxDB.ConsistencyLevel.ALL).build();
            batchPoints.point(point);
            records.add(batchPoints.lineProtocol());
        });
        influxDbUtils.batchInsert(influxDbConfig.getDatabase(),"", InfluxDB.ConsistencyLevel.ALL, records);
    }

    /**
     * -------------------------------------------------end-------------------------------------------------------------
     */


    /**
     * 用能数据完整性数据
     * -------------------------------------------------start-----------------------------------------------------------
     */
    @GetMapping("eleIntegrityJob")
    public void eleIntegrityJobHandler() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)-1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.set(calendar2.get(Calendar.YEAR), calendar2.get(Calendar.MONTH), calendar2.get(Calendar.DAY_OF_MONTH)-1, 23, 59, 59);
        calendar2.set(Calendar.MILLISECOND, 0);
        String startTime = format.format(calendar.getTime());
        String endTime = format.format(calendar2.getTime());

        List<HarmonicDTO> powerData = getPowerData(startTime,endTime);
        if(!CollectionUtils.isEmpty(powerData)){
            createMeasurement(powerData,calendar.getTimeInMillis());
        } else {
            List<HarmonicDTO> result = new ArrayList<>();
            //查询当前网关下所有监测点id
            List<String> lineList = eleIntegrityFeignClient.getPowerLineId().getData();
            lineList.forEach(item->{
                HarmonicDTO harmonicDTO = new HarmonicDTO();
                harmonicDTO.setId(item);
                harmonicDTO.setReal(0);
                harmonicDTO.setDue(96);
                result.add(harmonicDTO);
            });
            createMeasurement(result,calendar.getTimeInMillis());
        }
        List<HarmonicDTO> airData = getAirData(startTime,endTime);
        if(!CollectionUtils.isEmpty(airData)){
            powerData = new ArrayList<>(airData);
            createMeasurement(powerData,calendar.getTimeInMillis());
        } else {
            List<HarmonicDTO> result = new ArrayList<>();
            //查询当前网关下所有监测点id
            List<String> lineList = eleIntegrityFeignClient.getAirLineId().getData();
            lineList.forEach(item->{
                HarmonicDTO harmonicDTO = new HarmonicDTO();
                harmonicDTO.setId(item);
                harmonicDTO.setReal(0);
                harmonicDTO.setDue(288);
                result.add(harmonicDTO);
            });
            createMeasurement(result,calendar.getTimeInMillis());
        }
    }

    /**
     * 生成power_data数据
     */
    private List<HarmonicDTO> getPowerData(String startTime, String endTime){
        List<HarmonicDTO> list = new ArrayList<>();
        String sql = "SELECT count(FundWattHr) FROM power_data where time >= '"+startTime+"' and time <= '"+endTime+"' group by LineId";
        QueryResult sqlResult = influxDbUtils.query(sql);
        //处理结果集
        List<QueryResult.Series> seriesList = sqlResult.getResults().get(0).getSeries();
        if (!CollectionUtils.isEmpty(seriesList)){
            seriesList.forEach(po -> {
                HarmonicDTO harmonicDTO = new HarmonicDTO();
                String lineId = po.getTags().get("LineId");
                List<List<Object>> countList = po.getValues();
                for (List<Object> value : countList) {
                    //当日实际数据
                    Integer count =  new BigDecimal(value.get(1).toString()).intValue();
                    harmonicDTO.setId(lineId);
                    harmonicDTO.setReal(count);
                    harmonicDTO.setDue(POWER_DATA_DUE);
                }
                list.add(harmonicDTO);
            });
        }
        return list;
    }

    /**
     * 生成air_data数据
     */
    private List<HarmonicDTO> getAirData(String startTime, String endTime){
        List<HarmonicDTO> list = new ArrayList<>();
        String sql = "SELECT count(ACInMode),count(ACOutMode) FROM air_data where time >='"+startTime+"' and time <= '"+endTime+"' group by LineId";
        QueryResult sqlResult = influxDbUtils.query(sql);
        //处理结果集
        List<QueryResult.Series> seriesList = sqlResult.getResults().get(0).getSeries();
        if (!CollectionUtils.isEmpty(seriesList)){
            seriesList.forEach(po -> {
                HarmonicDTO harmonicDTO = new HarmonicDTO();
                String lineId = po.getTags().get("LineId");
                List<List<Object>> countList = po.getValues();
                for (List<Object> value : countList) {
                    //当日实际数据
                    if (!Objects.isNull(value.get(1))){
                        harmonicDTO.setReal(new BigDecimal(value.get(1).toString()).intValue());
                    } else {
                        harmonicDTO.setReal(new BigDecimal(value.get(2).toString()).intValue());
                    }
                    harmonicDTO.setId(lineId);
                    harmonicDTO.setDue(AIR_DATA_DUE);
                }
                list.add(harmonicDTO);
            });
        }
        return list;
    }

    /**
     * 生成用能数据完整性表
     */
    private void createMeasurement(List<HarmonicDTO> list, long time){
        List<String> records = new ArrayList<String>();
        list.forEach(item->{
            Map<String, String> tags = new HashMap<>();
            Map<String, Object> fields = new HashMap<>();
            tags.put("line_id",item.getId());
            fields.put("real",item.getReal());
            fields.put("due",item.getDue());
            Point point = influxDbUtils.pointBuilder("ele_integrity", time, TimeUnit.MILLISECONDS, tags, fields);
            BatchPoints batchPoints = BatchPoints.database(influxDbConfig.getDatabase()).tag("line_id", item.getId()).retentionPolicy("").consistency(InfluxDB.ConsistencyLevel.ALL).build();
            batchPoints.point(point);
            records.add(batchPoints.lineProtocol());
        });
        influxDbUtils.batchInsert(influxDbConfig.getDatabase(),"", InfluxDB.ConsistencyLevel.ALL, records);
    }

    /**
     * -------------------------------------------------end-------------------------------------------------------------
     */
}
