package com.yeejoin.equipmanage.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.equipmanage.common.enums.PressurePumpRelateEnum;
import com.yeejoin.equipmanage.common.vo.IotDataVO;
import com.yeejoin.equipmanage.fegin.IotFeign;
import com.yeejoin.equipmanage.service.IPressurePumpService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PressurePumpServiceImpl implements IPressurePumpService {

    @Autowired
    private IotFeign iotFeign;

    @Autowired
    private RedisUtils redisUtils;

    @Value("classpath:/json/nameKeyInfo.json")
    private Resource nameKeyInfo;

    @Value("${equipment.pressurepump.start}")
    private String pressurePumpStart;

    @Value("${equipment.pressurepump.pipepressure}")
    private String pressurePumpPipePressure;

    @Override
    @Async
    public void saveDataToRedis(List<IotDataVO> iotDatalist, String topic) {
        String pressurePumpValue = PressurePumpRelateEnum.PRESSURE_PUMP.getValue();
        //  获取配置JSON信息集合
        List<Map> list = getNameKeyInfoList(pressurePumpValue);
        if (CollectionUtils.isNotEmpty(list)) {
            Map map = list.get(0);
            String nameKey = map.get("nameKey").toString();
            int expire = Integer.parseInt(map.get("expire").toString());
            String nowString = DateUtils.getDateNowString();
            long timeMillis = System.currentTimeMillis();
            for (IotDataVO vo : iotDatalist) {
                String key = vo.getKey();
                if (nameKey.contains(vo.getKey())) {
                    vo.setCreatedTime(nowString);
                    String[] split = topic.split("/");
                    topic = split.length > 2 ? String.join("", split[0], split[1]) : "";
                    redisUtils.set(String.join(":", pressurePumpValue, key, topic, String.valueOf(timeMillis)), JSONObject.toJSONString(vo), expire);
                }
            }
        }
    }

    @Override
    public List<IotDataVO> getDataToRedis(String infoCode, String nameKey, String iotCode) {
        List<IotDataVO> list = new ArrayList<>();
        Set<String> keys = redisUtils.getKeys(String.join(":", infoCode, nameKey, StringUtils.isNotEmpty(iotCode) ? iotCode : ""));
        if (CollectionUtils.isNotEmpty(keys)) {
            keys.forEach(x -> {
                list.add(JSON.parseObject(redisUtils.get(x).toString(), IotDataVO.class));
            });
            //  时间倒序排序
            list.sort((t1, t2) -> t2.getCreatedTime().compareTo(t1.getCreatedTime()));
        }
        return list;
    }

    @Override
    public List<IotDataVO> getDataToRedisByDateBetween(String infoCode, String nameKey, String iotCode, Date startDate, Date endDate) {
        List<IotDataVO> list = new ArrayList<>();
        Set<String> keys = redisUtils.getKeys(String.join(":", infoCode, nameKey, StringUtils.isNotEmpty(iotCode) ? iotCode : ""));
        if (CollectionUtils.isNotEmpty(keys)) {
            keys.forEach(x -> {
                String[] split = x.split(":");
                long time = split.length > 0 ? Long.parseLong(split[split.length - 1]) : 0;
                try {
                    Date date = DateUtils.convertStrToDate(DateUtils.stampToDate(time, DateUtils.DATE_TIME_PATTERN), DateUtils.DATE_TIME_PATTERN);
                    if (DateUtils.dateCompare(date, startDate) >= 0 && DateUtils.dateCompare(endDate, date) >= 0) {
                        list.add(JSON.parseObject(redisUtils.get(x).toString(), IotDataVO.class));
                    }
                } catch (ParseException e) {
                    log.error("getDataToRedisByDateBetween-->字符串转日期失败：{}", e.getMessage());
                }
            });
            //  时间倒序排序
            list.sort((t1, t2) -> t2.getCreatedTime().compareTo(t1.getCreatedTime()));
        }
        return list;
    }

    @Override
    public List<Map> getNameKeyInfoList(String code) {
        String json = null;
        try {
            json = IOUtils.toString(nameKeyInfo.getInputStream(), java.lang.String.valueOf(StandardCharsets.UTF_8));
        } catch (IOException e) {
            log.error("获取指标JSON配置信息失败：{}", e.getMessage());
        }
        List<Map> list = JSONObject.parseArray(json, Map.class);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.stream().filter(x -> code.equals(x.get("code"))).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public long getAllPressurePumpStartStopInterval(List<IotDataVO> dataList, String nowStrLong) {
        String intervalTime1 = nowStrLong;
        String intervalTime2 = nowStrLong;
        if (CollectionUtils.isNotEmpty(dataList)) {
            IotDataVO iotDataVO = dataList.get(0);
            String value = iotDataVO.getValue().toString();
            String createdTime = iotDataVO.getCreatedTime();
            List<IotDataVO> falseDataList = getRedisDataFilterList(dataList, PressurePumpRelateEnum.IOT_INDEX_VALUE_FALSE.getValue());
            if (PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue().equalsIgnoreCase(value)) {
                intervalTime1 = createdTime;
                if (CollectionUtils.isNotEmpty(falseDataList)) {
                    //  获取最新的停止时间
                    intervalTime2 = falseDataList.get(0).getCreatedTime();
                }
            } else {
                List<IotDataVO> trueDataList = getRedisDataFilterList(dataList, PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue());
                if (CollectionUtils.isNotEmpty(falseDataList) && CollectionUtils.isNotEmpty(trueDataList)) {
                    //  获取最新的启动时间
                    intervalTime1 = trueDataList.get(0).getCreatedTime();
                    //  获取大于启动信号，且最近停止信号的时间
                    String finalIntervalTime = intervalTime1;
                    List<IotDataVO> timeList = falseDataList.stream().filter(x -> DateUtils.getDurationSeconds(finalIntervalTime, x.getCreatedTime(), DateUtils.DATE_TIME_PATTERN) >= 0).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(timeList)) {
                        intervalTime2 = timeList.get(timeList.size() - 1).getCreatedTime();
                    }
                }
            }
        }
        //  结果向上取整
        double ceil = Math.ceil(Math.abs(DateUtils.getDurationSeconds(intervalTime1, intervalTime2, DateUtils.DATE_TIME_PATTERN)) * 1.0 / Double.parseDouble(PressurePumpRelateEnum.ONE_HOUR_MINUTE.getValue()));
        return new Double(ceil).longValue();
    }

    private List<IotDataVO> getRedisDataFilterList(List<IotDataVO> dataList, String value) {
        return dataList.stream().filter(x -> value.equalsIgnoreCase(x.getValue().toString())).collect(Collectors.toList());
    }

    private List<Map<String, String>> getIotDataFilterList(List<Map<String, String>> iotDataList, String value) {
        return iotDataList.stream().filter(x -> x.containsKey(PressurePumpRelateEnum.CREATED_TIME.getValue()) && value.equalsIgnoreCase(x.get(pressurePumpStart))).collect(Collectors.toList());
    }

    private List<IotDataVO> getRedisDataFilterList(List<IotDataVO> dataList, String value, Date beforeDate) {
        if (beforeDate != null) {
            return dataList.stream().filter(x -> DateUtils.dateCompare(DateUtils.longStr2Date(x.getCreatedTime()), beforeDate) >= 0 && value.equalsIgnoreCase(x.getValue().toString())).collect(Collectors.toList());
        }
        return dataList.stream().filter(x -> value.equalsIgnoreCase(x.getValue().toString())).collect(Collectors.toList());
    }

    private List<Map<String, String>> getIotDataFilterList(List<Map<String, String>> iotDataList, String value, Date beforeDate) {
        if (beforeDate != null) {
            return iotDataList.stream().filter(x -> x.containsKey(PressurePumpRelateEnum.CREATED_TIME.getValue()) && DateUtils.dateCompare(DateUtils.longStr2Date(x.get(PressurePumpRelateEnum.CREATED_TIME.getValue())), beforeDate) >= 0 && value.equalsIgnoreCase(x.get(pressurePumpPipePressure))).collect(Collectors.toList());
        }
        return iotDataList.stream().filter(x -> x.containsKey(PressurePumpRelateEnum.CREATED_TIME.getValue()) && value.equalsIgnoreCase(x.get(pressurePumpPipePressure))).collect(Collectors.toList());
    }

    @Override
    public int getAllPressurePumpStartFrequency(double hour, Date dateNow) {
        List<IotDataVO> list = getDataToRedis(PressurePumpRelateEnum.PRESSURE_PUMP.getValue(), pressurePumpStart, null);
        if (CollectionUtils.isNotEmpty(list)) {
            Date beforeDate = DateUtils.dateAddMinutes(dateNow, (int) (hour * Integer.parseInt(PressurePumpRelateEnum.ONE_HOUR_MINUTE.getValue()) * -1));
            List<IotDataVO> collect = list.stream().filter(x -> DateUtils.dateCompare(DateUtils.longStr2Date(x.getCreatedTime()), beforeDate) >= 0 && PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue().equalsIgnoreCase(x.getValue().toString())).collect(Collectors.toList());
            return collect.size();
        }
        return 0;
    }

    @Override
    public long getAllPressurePumpStartStopDuration(List<IotDataVO> dataList, String nowStrLong) {
        String durationTime = nowStrLong;
        if (CollectionUtils.isNotEmpty(dataList)) {
            IotDataVO iotDataVO = dataList.get(0);
            String value = iotDataVO.getValue().toString();
            String createdTime = iotDataVO.getCreatedTime();
            if (PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue().equalsIgnoreCase(value)) {
                durationTime = createdTime;
            } else {
                List<IotDataVO> falseDataList = getRedisDataFilterList(dataList, PressurePumpRelateEnum.IOT_INDEX_VALUE_FALSE.getValue());
                List<IotDataVO> trueDataList = getRedisDataFilterList(dataList, PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue());
                if (CollectionUtils.isNotEmpty(falseDataList) && CollectionUtils.isNotEmpty(trueDataList)) {
                    //  获取最新启动时间
                    durationTime = trueDataList.get(0).getCreatedTime();
                    //  获取大于启动信号，且最近停止信号的时间
                    String finalDurationTime = durationTime;
                    List<IotDataVO> timeList = falseDataList.stream().filter(x -> DateUtils.getDurationSeconds(finalDurationTime, x.getCreatedTime(), DateUtils.DATE_TIME_PATTERN) >= 0).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(timeList)) {
                        nowStrLong = timeList.get(timeList.size() - 1).getCreatedTime();
                    }
                }
            }
        }
        //  结果向上取整
        double ceil = Math.ceil(Math.abs(DateUtils.getDurationSeconds(durationTime, nowStrLong, DateUtils.DATE_TIME_PATTERN)) * 1.0 / Double.parseDouble(PressurePumpRelateEnum.ONE_HOUR_MINUTE.getValue()));
        return new Double(ceil).longValue();
    }

    @Override
    public double getAllPressurePumpPipePressureDiff(List<IotDataVO> dataList, List<IotDataVO> dataPipeList,  String minutes) {
        if (CollectionUtils.isNotEmpty(dataList) && CollectionUtils.isNotEmpty(dataPipeList)) {
            IotDataVO iotDataVO = dataList.get(0);
            String value = iotDataVO.getValue().toString();
            if (PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue().equalsIgnoreCase(value)) {
                List<IotDataVO> falseDataList = getRedisDataFilterList(dataList, PressurePumpRelateEnum.IOT_INDEX_VALUE_FALSE.getValue());
                if (CollectionUtils.isNotEmpty(falseDataList)) {
                    String createdTime = falseDataList.get(0).getCreatedTime();
                    try {
                        Date stop5BeforeDate = DateUtils.dateAddMinutes(DateUtils.convertStrToDate(createdTime, DateUtils.DATE_TIME_PATTERN), Integer.parseInt(minutes));
                        //  获取指定之前时间，指定值数据
                        List<IotDataVO> dataFilterList = getRedisDataFilterList(dataPipeList, value, stop5BeforeDate);
                        if (CollectionUtils.isNotEmpty(dataFilterList)) {
                            double val1 = Double.parseDouble(dataPipeList.get(0).getValue().toString());
                            double val2 = Double.parseDouble(dataFilterList.get(dataFilterList.size() - 1).getValue().toString());
                            return Math.abs(val1 - val2);
                        }
                    } catch (ParseException e) {
                        log.error("获取所有稳压泵管网压力差失败：{}", e.getMessage());
                    }
                }
            }
        }
        return 0;
    }

    @Override
    public List<Map<String, String>> getIotTopSingleField(String top, String productKey, String deviceName, String key, String fieldKey) {
        ResponseModel responseModel = iotFeign.topSingleField(top, productKey, deviceName, key, fieldKey);
        if (responseModel != null && 200 == responseModel.getStatus()) {
            String json = JSON.toJSONString(responseModel.getResult());
            return (List<Map<String, String>>) JSONArray.parse(json);
        }
        return Collections.emptyList();
    }

    @Override
    public List<Map<String, String>> getIotCommonListData(String startTime, String endTime, String prefix, String suffix, String key, String fieldKey) {
        ResponseModel responseModel = iotFeign.selectListNew(prefix, suffix, startTime, endTime, key, fieldKey);
        if (responseModel != null && 200 == responseModel.getStatus()) {
            String json = JSON.toJSONString(responseModel.getResult());
            return (List<Map<String, String>>) JSONArray.parse(json);
        }
        return Collections.emptyList();
    }

}
