package com.yeejoin.equipmanage.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeejoin.equipmanage.common.entity.SupervisionVideo;
import com.yeejoin.equipmanage.common.entity.vo.AlamVideoVO;
import com.yeejoin.equipmanage.common.enums.PressurePumpRelateEnum;
import com.yeejoin.equipmanage.common.utils.DateUtils;
import com.yeejoin.equipmanage.common.vo.IotDataVO;
import com.yeejoin.equipmanage.common.vo.PressurePumpCountVo;
import com.yeejoin.equipmanage.common.vo.StationMessage;
import com.yeejoin.equipmanage.fegin.IotFeign;
import com.yeejoin.equipmanage.mapper.FireFightingSystemMapper;
import com.yeejoin.equipmanage.mapper.SupervisionVideoMapper;
import com.yeejoin.equipmanage.service.IEquipmentSpecificSerivce;
import com.yeejoin.equipmanage.service.IPressurePumpService;
import com.yeejoin.equipmanage.service.ISupervisionVideoService;
import com.yeejoin.equipmanage.service.IVideoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.DateTimeUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static org.typroject.tyboot.core.foundation.context.RequestContext.*;
import static org.typroject.tyboot.core.foundation.utils.DateTimeUtil.ISO8601_DATE_HOUR_MIN_SEC;


@Slf4j
@Service
//@EnableAsync
public class SupervisionVideoServiceImpl extends ServiceImpl<SupervisionVideoMapper, SupervisionVideo> implements ISupervisionVideoService {

    @Autowired
    SupervisionVideoMapper supervisionVideoMapper;

    @Autowired
    private IVideoService videoService;
    @Autowired
    private IPressurePumpService pressurePumpService;

    @Autowired
    private IEquipmentSpecificSerivce equipmentSpecificSerivce;

    @Autowired
    private FireFightingSystemMapper fireFightingSystemMapper;

    @Autowired
    private IotFeign iotFeign;

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

    @Override
    public List<AlamVideoVO> queryVideoList(String bizOrgCode) {
        List<AlamVideoVO> list = supervisionVideoMapper.getVideoByCompany(bizOrgCode);
        if (0 < list.size()) {
            list.forEach(action -> {
                action.setVedioFormat(action.getVideoType());
                action.setUrl(videoService.getVideoUrl(action.getName(), action.getPresetPosition(), action.getUrl(), action.getCode()));
            });
        }
        return list;
    }


    @Override
    public boolean replaceVideo(Map<String, String> map, String bizOrgCode) {
        supervisionVideoMapper.delete(new QueryWrapper<SupervisionVideo>().eq("biz_org_code", bizOrgCode));
        List<SupervisionVideo> list = new ArrayList<>();
        String ids = map.get("ids");
        if (StringUtils.isNotEmpty(ids)) {
            for (String s : ids.split(",")) {
                SupervisionVideo supervisionVideo = new SupervisionVideo();
                supervisionVideo.setCameraId(s);
                supervisionVideo.setBizOrgCode(bizOrgCode);
                supervisionVideo.setId(Long.valueOf(String.valueOf(UUID.randomUUID().getLeastSignificantBits()).replace("-", "")));
                list.add(supervisionVideo);
            }
        }
        return saveBatch(list);
    }

    @Override
    public List<String> queryVideoAllId(String bizOrgCode) {
        return supervisionVideoMapper.queryVideoAllId(bizOrgCode);
    }

    @Override
    public Page<Map<String, Object>> queryPumpInfo(Page page, String bizOrgCode) {
        //  从 json 配置文件获取配置信息
        List<Map> infoList = pressurePumpService.getNameKeyInfoList(PressurePumpRelateEnum.PRESSURE_PUMP.getValue());
        Page<Map<String, Object>> pressurePumpInfo = new Page<>();
        if (!CollectionUtils.isEmpty(infoList)) {
            Map map = infoList.get(0);
            String equipmentCode = map.get("equipmentCode").toString();
            String top = map.get("top").toString();
            String countRedisKey = map.get("countRedisKey").toString();
            long countExpire = Long.parseLong(map.get("countExpire").toString());
            Date dateNow = DateUtils.getDateNow();
            String nowStrLong = DateUtils.getNowStrLong();
            //  获取稳压泵数据，redis没有，从iot取
            List<Map<String, Object>> pumpInfoList = equipmentSpecificSerivce.getFirePumpInfoEQ(equipmentCode, bizOrgCode);
            Map<String, List<IotDataVO>> dataMap = pressurePumpService.getDataList(pumpInfoList, PressurePumpRelateEnum.PRESSURE_PUMP.getValue(), equipmentCode, top, pressurePumpStart, bizOrgCode, null);
            List<IotDataVO> dataListFilterTrue = dataMap.get("dataListFilterTrue");
            List<IotDataVO> dataListFilterFalse = dataMap.get("dataListFilterFalse");
            Long interval = 0L;
            //全部稳压泵半小时、一小时、两小时、四小时启动次数
            int halfHourStartNum = pressurePumpService.getAllPressurePumpStartFrequency(Double.parseDouble(PressurePumpRelateEnum.HALF_HOUR.getValue()), dataListFilterTrue, dateNow);
            int oneHourStartNum = pressurePumpService.getAllPressurePumpStartFrequency(Double.parseDouble(PressurePumpRelateEnum.ONE_HOUR.getValue()), dataListFilterTrue, dateNow);
            int twoHourStartNum = pressurePumpService.getAllPressurePumpStartFrequency(Double.parseDouble(PressurePumpRelateEnum.TWO_HOUR.getValue()), dataListFilterTrue, dateNow);
            int fourHourStartNum = pressurePumpService.getAllPressurePumpStartFrequency(Double.parseDouble(PressurePumpRelateEnum.FOUR_HOUR.getValue()), dataListFilterTrue, dateNow);
            //  近3天启动平均值，四合五入
            AtomicInteger dayAvgFrequency = new AtomicInteger();
            try {
                Date startDate = com.yeejoin.amos.boot.biz.common.utils.DateUtils.dateAddDays(dateNow, Integer.parseInt(PressurePumpRelateEnum.DAY_AVG.getValue()) + 1);
                String startTime = String.join(" ", com.yeejoin.amos.boot.biz.common.utils.DateUtils.dateFormat(startDate, com.yeejoin.amos.boot.biz.common.utils.DateUtils.DATE_PATTERN), "00:00:00");
                String endTime = String.join(" ", com.yeejoin.amos.boot.biz.common.utils.DateUtils.dateFormat(dateNow, com.yeejoin.amos.boot.biz.common.utils.DateUtils.DATE_PATTERN), "23:59:59");
                Map<String, List<PressurePumpCountVo>> dayAvgDataMap = pressurePumpService.getDateRangeCountList(pumpInfoList, startTime,endTime, PressurePumpRelateEnum.PRESSURE_PUMP.getValue(), countRedisKey, equipmentCode, pressurePumpStart, countExpire, bizOrgCode);
                if (!CollectionUtils.isEmpty(dayAvgDataMap)) {
                    for (List<PressurePumpCountVo> voList : dayAvgDataMap.values()) {
                        if (!CollectionUtils.isEmpty(voList)) {
                            voList.forEach(x -> dayAvgFrequency.addAndGet(x.getValue()));
                        }
                    }
                }
            } catch (ParseException e) {
                log.error("近3天平均启动次数获取失败-->dayAvgFrequency：{}", e.getMessage());
            }
            DecimalFormat df = new DecimalFormat("0.0");
            int dayAvgCount = dayAvgFrequency.get();
            String dayAvgStartNum = dayAvgCount == 0 ? "0" : df.format(dayAvgCount / (double) Math.abs(Integer.parseInt(PressurePumpRelateEnum.DAY_AVG.getValue())));
            pressurePumpInfo = fireFightingSystemMapper.getPressurePumpInfo(page, bizOrgCode, null);
            String prefix = null;
            // 获取redis稳压泵缓存数据，默认JSON配置最近4小时
            //List<IotDataVO> DataList = pressurePumpService.getDataToRedis(PressurePumpRelateEnum.PRESSURE_PUMP.getValue(), pressurePumpStart, null, bizOrgCode);
            List<IotDataVO> dateList2 = new ArrayList<>();
            for (Map<String, Object> item : pressurePumpInfo.getRecords()) {

                String suffix = null;
                String iotCode = item.get("iot_code").toString();
                if (iotCode.length() > 8) {
                    prefix = iotCode.substring(0, 8);
                    suffix = iotCode.substring(8);
                } else {
                    throw new BadRequest("装备物联编码错误，请确认！");
                }
                Date mounthDate = null;
                try {
                    mounthDate = DateUtils.getCurrentMonthStartTime(new Date());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                String startDateStr = DateUtils.convertDateToString(mounthDate, DateUtils.DATE_TIME_PATTERN);
                //稳压泵本月累计启动统计
                List<Map<String, String>> mounthEntity =
                        pressurePumpService.getIotCommonListData(startDateStr, nowStrLong, prefix, suffix, (PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue()), pressurePumpStart);
                item.put("monthStartNum", ObjectUtils.isEmpty(mounthEntity) ? 0 : mounthEntity.size());
                item.put("halfHourStartNum", halfHourStartNum);
                item.put("oneHourStartNum", oneHourStartNum);
                item.put("twoHourStartNum", twoHourStartNum);
                item.put("fourHourStartNum", fourHourStartNum);
                item.put("dayAvgStartNum", dayAvgStartNum);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                long nowDateTime = new Date().getTime();//当前时间戳
                boolean time = true;
                //获取最近的一个触发物联指标的时间
                Map<String, String> stateMap = fireFightingSystemMapper.queryPressureNowSignalBySpecificId((Long) item.get("id"));
                Long update_date = 0L;
                if (!ObjectUtils.isEmpty(stateMap)) {
                    try {
                        //如果当前指标为启动，并且指标值为true,计算启动时长
                        if(PressurePumpRelateEnum.START.getDesc().contains(stateMap.get("equipment_index_name")) && PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue().contains(stateMap.get("value"))){
                            update_date = sdf.parse(stateMap.get("update_date")).getTime();
                            long res = nowDateTime - update_date;
                            long diffMinute = res / 1000 / 60;
                            if (diffMinute > Long.valueOf(PressurePumpRelateEnum.START_FIVE.getValue())) {
                                time = false;
                            }
                        }
                        if(PressurePumpRelateEnum.IOT_INDEX_VALUE_FALSE.getValue().contains(stateMap.get("value"))){
                            if(PressurePumpRelateEnum.START.getDesc().contains(stateMap.get("equipment_index_name"))){
                                item.put("equipment_index_name", PressurePumpRelateEnum.STOP.getDesc());
                            } else {
                                item.put("equipment_index_name", PressurePumpRelateEnum.RESET.getDesc());
                            }
                        } else {
                            item.put("equipment_index_name", stateMap.get("equipment_index_name"));
                        }
                        item.put("update_time", stateMap.get("update_date"));
                    } catch (ParseException e) {
                        throw new BadRequest("稳压泵最新指标时间转换失败！");
                    }
                } else {
                    item.put("equipment_index_name", "无信号");
                    item.put("update_time", false);
                }
                    //从influxdb中获取最近一次启停间隔
                    List<Map<String, String>> iotDataList = pressurePumpService.getIotTopSingleField(top, prefix, suffix, null, pressurePumpStart);
                    iotDataList.forEach(e -> {
                        try {
                            IotDataVO iotDataVO = (IotDataVO) pressurePumpService.mapToObject(e, IotDataVO.class, pressurePumpStart);
                            dateList2.add(iotDataVO);
                        } catch (Exception el) {
                            throw new RuntimeException();
                        }
                    });
                //稳压泵当前状态   无告警并且启动时长小于5分钟为正常
//                item.put("stateDesc", Integer.parseInt(String.valueOf(item.get("isAlarm"))) == 0 && time ? PressurePumpRelateEnum.PIPE_PRESSURE_NORMAL_STATUS.getValue() : PressurePumpRelateEnum.PIPE_PRESSURE_ABNORMAL_STATUS.getValue());
            }

            interval =pressurePumpService.getAllPressurePumpStartStopInterval(dateList2, dataListFilterTrue, dataListFilterFalse, nowStrLong);

            double finalDiffMinute = (double) interval;
            pressurePumpInfo.getRecords().stream(
            ).map(item -> {
                item.put("startAndStopInterval", finalDiffMinute);
                if (finalDiffMinute <= Long.valueOf(PressurePumpRelateEnum.START_FIVE.getValue())) {
                    item.put("generalState", PressurePumpRelateEnum.PIPE_PRESSURE_ABNORMAL_STATUS.getValue());
                } else {
                    item.put("generalState", PressurePumpRelateEnum.PIPE_PRESSURE_NORMAL_STATUS.getValue());
                }
                item.put("nameKey", pressurePumpStart);
                return item;
            }).collect(Collectors.toList());
            List<Map<String, Object>> records = pressurePumpInfo.getRecords();
//            records.sort((t1, t2) -> {
//                if(t1.get("update_time") instanceof Boolean) {
//                    return  -1;
//                } else if (t2.get("update_time") instanceof Boolean) {
//                    return  -1;
//                } else {
//                    try {
//                        Long s1 = DateUtils.dateParse(DateUtils.DATE_TIME_PATTERN, t1.get("update_time").toString()).getTime();
//                        Long s2 = DateUtils.dateParse(DateUtils.DATE_TIME_PATTERN, t2.get("update_time").toString()).getTime();
//                        return s1.compareTo(s2);
//                    } catch (ParseException e) {
//                        e.printStackTrace();
//                        return -1;
//                    }
//                }
//            });
            pressurePumpInfo.setRecords(records);
        }
        return pressurePumpInfo;
    }

    @Override
    public List<Map<String, Object>> selectPressureDetails(String bizOrgCode, String id, String startTime, String endTime) {
        List<Map<String, Object>> pressurePumpInfo = fireFightingSystemMapper.selectAllPressurePumpInfo(bizOrgCode, id);
        pressurePumpInfo.stream().map(item -> {
            String prefix = null;
            String suffix = null;
            String iotCode = item.get("iot_code").toString();
            if (iotCode.length() > 8) {
                prefix = iotCode.substring(0, 8);
                suffix = iotCode.substring(8);
            } else {
                throw new BadRequest("装备物联编码错误，请确认！");
            }
            //通过iot最近一次的启动和停止时间
            List<Map<String, String>> trueData = pressurePumpService.getIotTopSingleField(PressurePumpRelateEnum.ONE_TIME.getValue(), prefix, suffix, PressurePumpRelateEnum.IOT_INDEX_VALUE_TRUE.getValue(), pressurePumpStart);
            List<Map<String, String>> falseData = pressurePumpService.getIotTopSingleField(PressurePumpRelateEnum.ONE_TIME.getValue(), prefix, suffix, PressurePumpRelateEnum.IOT_INDEX_VALUE_FALSE.getValue(), pressurePumpStart);
            if(!ObjectUtils.isEmpty(trueData)){
                item.put("startTime", trueData.get(0).get("createdTime"));
            } else {
                item.put("startTime", "");
            }
            if(!ObjectUtils.isEmpty(falseData)){
                item.put("stopTime", falseData.get(0).get("createdTime"));
            } else {
                item.put("stopTime", "");
            }
            return item;
        }).collect(Collectors.toList());
        List<Map<String, Object>> list = filterByTimestamp(pressurePumpInfo, startTime, endTime);
        return list;
    }

    private List<Map<String, Object>> filterByTimestamp(List<Map<String, Object>> objects, String startTime, String endTime) {
        if (ObjectUtils.isEmpty(startTime) && ObjectUtils.isEmpty(endTime)) {
            return objects; // 如果起止时间都为空，则返回原始列表
        } else if (ObjectUtils.isEmpty(startTime)) {
            return objects.stream()
                    .filter(obj -> !ObjectUtils.isEmpty(obj.get("startTime")))
                    .filter(obj -> DateUtil.parse(obj.get("startTime").toString(), DatePattern.NORM_DATETIME_PATTERN).isBefore(DateUtil.parse(endTime, DatePattern.NORM_DATETIME_PATTERN)))
                    .collect(Collectors.toList());
        } else if (ObjectUtils.isEmpty(endTime)) {
            return objects.stream()
                    .filter(obj -> !ObjectUtils.isEmpty(obj.get("startTime")))
                    .filter(obj -> DateUtil.parse(obj.get("startTime").toString(), DatePattern.NORM_DATETIME_PATTERN).isAfter(DateUtil.parse(startTime, DatePattern.NORM_DATETIME_PATTERN)))
                    .collect(Collectors.toList());
        } else {
            return objects.stream()
                    .filter(obj -> !ObjectUtils.isEmpty(obj.get("startTime")))
                    .filter(obj -> DateUtil.parse(obj.get("startTime").toString(), DatePattern.NORM_DATETIME_PATTERN).isAfter(DateUtil.parse(startTime, DatePattern.NORM_DATETIME_PATTERN)) && DateUtil.parse(obj.get("startTime").toString(), DatePattern.NORM_DATETIME_PATTERN).isBefore(DateUtil.parse(endTime, DatePattern.NORM_DATETIME_PATTERN)))
                    .collect(Collectors.toList());
        }
    }

    @Override
    public Map<String, Object> getPressurePumpPage(String bizOrgCode, String id, String startTime, String endTime, String pageNum, String pageSize, String timeSort, String stateSort) {
        List<Map<String, Object>> pressurePumpInfo = fireFightingSystemMapper.selectAllPressurePumpInfoByBizOrgCode(bizOrgCode, id);
        List<Map<String, String>> resList = new ArrayList<>();
        List<Map<String, String>> finalResList = resList;
        pressurePumpInfo.stream().forEach(item -> {
            String prefix = null;
            String suffix = null;
            String iotCode = item.get("iot_code").toString();
            if (iotCode.length() > 8) {
                prefix = iotCode.substring(0, 8);
                suffix = iotCode.substring(8);
            } else {
                throw new BadRequest("装备物联编码错误，请确认！");
            }
            ResponseModel entity = null;
            try {
                entity = iotFeign.selectPage(getAppKey(), getProduct(), getToken(), startTime, endTime, prefix, suffix, pressurePumpStart, 0, 1000);
            } catch (Exception e) {
                throw new RuntimeException("调用AMOS-API-IOT服务失败，请检查服务是否正常！");
            }

            if (200 == entity.getStatus() && !ObjectUtils.isEmpty(entity.getResult())) {
                String json = JSON.toJSONString(entity.getResult());
                JSONObject messageObj = JSONObject.parseObject(json);
                JSONArray array = messageObj.getJSONArray("records");
                List<Map<String, String>> listObject = (List<Map<String, String>>) JSONArray.parse(JSON.toJSONString(array));
                listObject.forEach(x -> {
                    Map<String, String> map = new HashMap<>();
                    map.put("id", UUID.randomUUID().toString());
                    map.put("name", String.valueOf(item.get("name")));
                    try {
                        map.put("time", change(String.valueOf(x.get("time"))));
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                    map.put("value", String.valueOf(x.get(pressurePumpStart)));
                    finalResList.add(map);
                });
            }
        });
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("current", Integer.valueOf(pageNum));
        resMap.put("pageSize", Integer.valueOf(pageSize));
        resMap.put("total", finalResList.size());
        if (ObjectUtils.isEmpty(finalResList)) {
            resMap.put("pages", 0);
            resMap.put("records", new ArrayList<>());
            return resMap;
        } else {
            resList = finalResList.stream().sorted((t1, t2) -> t2.get("time").compareTo(t1.get("time"))).collect(Collectors.toList());
        }
        if (StringUtils.isNotEmpty(timeSort)) {
            if ("0".equals(timeSort)) {
                resList = finalResList.stream().sorted(Comparator.comparing(t -> t.get("time"))).collect(Collectors.toList());
            }
        }
        if (StringUtils.isNotEmpty(stateSort)) {
            if ("1".equals(stateSort)) {
                resList = resList.stream().sorted((t1, t2) -> t2.get("value").compareTo(t1.get("value"))).collect(Collectors.toList());
            } else {
                resList = resList.stream().sorted(Comparator.comparing(t -> t.get("value"))).collect(Collectors.toList());
            }
        }
        int startIndex = (Integer.valueOf(pageNum) - 1) * Integer.valueOf(pageSize);
        int endIndex = Math.min(startIndex + Integer.valueOf(pageSize), resList.size());
        int pages = (finalResList.size() + Integer.valueOf(pageSize) - 1) / Integer.valueOf(pageSize);
        List<Map<String, String>> list = resList.subList(startIndex, endIndex);
        resMap.put("pages", pages);
        resMap.put("records", list);
        return resMap;
    }

    @Override
    public List<Map<String, Object>> selectAllPressureName(String bizOrgCode) {
        return fireFightingSystemMapper.selectAllPressureName(bizOrgCode);
    }

    private String change(String time) throws ParseException {
        Date date1 = null;
        try {
            String strDate = time.substring(0, 19);
            SimpleDateFormat sdf = new SimpleDateFormat(ISO8601_DATE_HOUR_MIN_SEC);
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
            date1 = sdf.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return DateTimeUtil.format(date1, DateTimeUtil.ISO_DATE_HOUR24_MIN_SEC);
    }
}
