package com.njcn.cloud.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.cloud.enums.app.UserCodeEnum;
import com.njcn.cloud.pojo.dto.*;
import com.njcn.cloud.service.*;
import com.njcn.cloud.utils.RedisDB;
import com.njcn.cloud.utils.SmsUtil;
import com.njcn.common.pojo.dto.LogInfoDTO;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils;
import com.njcn.device.pq.api.DeptLineFeignClient;
import com.njcn.device.pq.api.GeneralDeviceInfoClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.pojo.param.OnlineRateParam;
import com.njcn.device.pq.pojo.po.DeptLine;
import com.njcn.device.pq.pojo.po.TopMsgPO;
import com.njcn.device.pq.pojo.vo.LineDetailVO;
import com.njcn.event.api.EventDetailFeignClient;
import com.njcn.event.file.component.WavePicComponent;
import com.njcn.event.file.pojo.bo.WaveDataDetail;
import com.njcn.event.file.pojo.dto.WaveDataDTO;
import com.njcn.event.file.utils.WaveUtil;
import com.njcn.event.pojo.po.RmpEventDetailPO;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.UserLogFeignClient;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.po.User;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.security.auth.login.AccountException;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author wr
 * @description
 * @date 2023/11/9 14:39
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MsgServiceImpl implements MsgService {

    private final EventDetailFeignClient eventDetailFeignClient;
    private final LineFeignClient lineFeignClient;
    private final DeptLineFeignClient deptLineFeignClient;
    private final UserLogFeignClient userLogFeignClient;
    private final DeptFeignClient deptFeignClient;
    private final UserFeignClient userFeignClient;
    private final GeneralDeviceInfoClient generalDeviceInfoClient;
    private final IAppEventInfoService appEventInfoService;
    private final WavePicComponent wavePicComponent;
    private final IAppInfoSetService appInfoSetService;
    private final IAppEventMsgService appEventMsgService;
    private final IAppSteadyMsgService appSteadyMsgService;
    private final IAppDevMsgService appDevMsgService;
    private final RedisUtil redisUtil;

    private final SmsUtil smsUtil;

    /**
     * 推送暂降消息
     *
     * @param eventDetailIndex 暂降事件索引
     * @param lineId           监测点索引
     *                         1：根据监测点获取绑定的部门
     *                         2：根据部门找到对应的主用户
     *                         3：根据主用户获取所有的app用户
     *                         4：执行推送保存功能
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void sendEventMsg(String eventDetailIndex, String lineId) throws Exception {
        List<RmpEventDetailPO> eventDetails = eventDetailFeignClient.getEventDetailByIdsList(Arrays.asList(eventDetailIndex)).getData();
        if (CollUtil.isEmpty(eventDetails)) {
            return;
        }
        RmpEventDetailPO eventDetail = eventDetails.get(0);
        if (eventDetail.getFeatureAmplitude() == null || eventDetail.getFeatureAmplitude() >= 0.9) {
            return;
        }
        DeptLine deptLines = deptLineFeignClient.getLineByLineIds(lineId).getData();
        //查询为空，则无人关注，不做推送处理，但是需要进行日志记录
        if (ObjectUtil.isNull(deptLines)) {
            noUserFocus(eventDetailIndex, lineId);
        }
        //存在则进行筛选用户操作
        List<String> deptIndexs = deptFeignClient.getUpByDeptIds(deptLines.getId()).getData();
        //查找出可以推送的用户
        List<User> appUsers = userFeignClient.getUserByDeptIds(deptIndexs).getData();
        if (CollectionUtils.isEmpty(appUsers)) {
            noUserFocus(eventDetailIndex, lineId);
        }

        AppEventInfo one = appEventInfoService.getOne(new LambdaQueryWrapper<AppEventInfo>()
                .eq(AppEventInfo::getEventdetailIndex, eventDetailIndex)
        );
        if (ObjectUtil.isNotNull(one)) {
            throw new BusinessException(UserCodeEnum.REPEAT_EVENT_INFO.getMsg());
        } else {
            WaveDataDTO waveDataDTO = appEventInfoService.analyseWave(eventDetailIndex, 2);
            //数据筛选,如果是双路电压的话，会存在2个波形数据
            List<WaveDataDetail> waveDataDetails = WaveUtil.filterWaveData(waveDataDTO);
            String instantPath = wavePicComponent.generateImageShun(waveDataDTO, waveDataDetails);
            String rmsPath = wavePicComponent.generateImageRms(waveDataDTO, waveDataDetails);
            one=new AppEventInfo();
            one.setEventdetailIndex(eventDetailIndex);
            one.setInstantwavePath(instantPath);
            one.setRmswavePath(rmsPath);
        }
        appEventInfoService.save(one);
        //获取到设备码开始执行推送并保存库的操作
        //排重设备ID
        int phonePushFlag = 0;
        List<String> codes = new ArrayList<>();
        for (User appUser : appUsers) {
            if (!codes.contains(appUser.getDevCode())) {
                codes.add(appUser.getDevCode());
                pushEventInfo(eventDetail, appUser, StringUtils.isEmpty(appUser.getDevCode()) ? null : appUser.getDevCode(), phonePushFlag);
                phonePushFlag = 1;
            }
        }
    }


    /**
     * 稳态消息推送
     *
     * @param userIndex 用户索引
     * @param timeID    统计时间
     * @param lineNum   监测点数
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public String sendSteadyMsg(String userIndex, String timeID, Integer lineNum) {
        List<User> users = userFeignClient.getUserByIdList(Arrays.asList(userIndex)).getData();
        AppInfoSet appInfoSet = appInfoSetService.getById(userIndex);
        if (CollUtil.isEmpty(users) || ObjectUtil.isNull(appInfoSet)) {
            throw new BusinessException(UserCodeEnum.NO_USER.getMsg());
        }
        LocalDateTime time = LocalDateTimeUtil.parse(timeID,DatePattern.NORM_DATE_PATTERN);
        //插入之前需要判断是否重复时间
        List<AppSteadyMsg> steadyMsgs = appSteadyMsgService.list(new LambdaQueryWrapper<AppSteadyMsg>()
                .eq(AppSteadyMsg::getTimeId, time)
                .eq(AppSteadyMsg::getLineNum, lineNum)
                .eq(AppSteadyMsg::getUserIndex, userIndex)
        );
        if (CollUtil.isNotEmpty(steadyMsgs)) {
          return  steadyMsgs.get(0).getSteadyIndex();
        }
        AppSteadyMsg steadyMsg = new AppSteadyMsg();
        steadyMsg.setLineNum(lineNum);
        steadyMsg.setSteadyIndex(IdUtil.simpleUUID());
        steadyMsg.setState(0);
        steadyMsg.setTimeId(time);
        steadyMsg.setUserIndex(userIndex);
        appSteadyMsgService.save(steadyMsg);
        if (appInfoSet.getTargetInfo() == 1 && StrUtil.isNotBlank(users.get(0).getDevCode())) {
            //发送稳态消息
            String date = LocalDateTimeUtil.format(time, DatePattern.NORM_DATE_PATTERN);
            String title = "稳态越限消息";
            String content = date + " 发生稳态越限监测点" + lineNum + "个";
            sendMsg( users.get(0).getDevCode(), title, content, "2");
        }
       return steadyMsg.getSteadyIndex();

    }

    /**
     * 终端消息推送
     *
     * @param userIndex 用户索引
     * @param timeID    统计时间
     * @param topID     异常消息id (pqs_top_msg)
     * @param flag      是否强制推送
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public String sendTargetMsg(String userIndex, String timeID, String topID, Integer flag) {
        List<User> users = userFeignClient.getUserByIdList(Arrays.asList(userIndex)).getData();
        AppInfoSet appInfoSet = appInfoSetService.getById(userIndex);
        if (CollUtil.isEmpty(users) || ObjectUtil.isNull(appInfoSet)) {
            throw new BusinessException(UserCodeEnum.NO_USER.getMsg());
        }
        LocalDateTime time = LocalDateTimeUtil.parse(timeID,DatePattern.NORM_DATE_PATTERN);

        AppDevMsg devMsg = appDevMsgService.getOne(new LambdaQueryWrapper<AppDevMsg>()
                .eq(AppDevMsg::getUserIndex, userIndex)
                .eq(AppDevMsg::getTimeId, time)
        );
        OnlineRateParam top=new OnlineRateParam();
        top.setIds(Arrays.asList(topID));
        top.setType(0);
        List<TopMsgPO> topMsgPOS = generalDeviceInfoClient.getTopMsgInfoByIds(top).getData();

        if (ObjectUtil.isNotNull(devMsg)) {
            if (appInfoSet.getDeviceInfo() == 1 && flag == 1) {
                sendDevMsg(timeID, topMsgPOS,users.get(0));
            }
        } else {
            devMsg = new AppDevMsg();
            devMsg.setDevmsgIndex(IdUtil.simpleUUID());
            devMsg.setTopId(topID);
            devMsg.setUserIndex(userIndex);
            devMsg.setTimeId(time);
            devMsg.setState(0);
            appDevMsgService.save(devMsg);
            if (appInfoSet.getDeviceInfo() == 1) {
                sendDevMsg(timeID, topMsgPOS,users.get(0));
            }
        }

        return devMsg.getDevmsgIndex();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void sendTerminalMsg(String userIndex,String devCode, String timeID,Integer devNum,Integer alarmNum,Integer comOutNum) {
        AppInfoSet appInfoSet = appInfoSetService.getById(userIndex);
        if (ObjectUtil.isNotNull(appInfoSet)) {
            if (appInfoSet.getDeviceInfo() == 1) {
                String title = timeID + "终端异常共" + devNum + "台";
                String content = "异常情况：" + (StringUtils.isEmpty(alarmNum) ? "" : "终端告警：" + alarmNum + "次  ") + (StringUtils.isEmpty(comOutNum) ? "" : "通讯中断：" + Integer.valueOf(comOutNum) + "次  ");
                sendMsg(devCode, title, content, "3");
            }
        } else {
            throw new BusinessException(UserCodeEnum.NO_USER_SETTING.getMsg());
        }
    }

    /**
     * 终端消息推送
     *
     * @param time
     * @param topMsgPOS
     */
    private void sendDevMsg(String time, List<TopMsgPO> topMsgPOS,User user) {
        if (CollUtil.isNotEmpty(topMsgPOS)) {
            TopMsgPO topMsgPO = topMsgPOS.get(0);
            Integer alarmNum = topMsgPO.getAlarmCount();
            Integer comOutNum = topMsgPO.getComOutCount();
            float flowNum = topMsgPO.getFlowValue();
            if (alarmNum > 0 || comOutNum > 0 || flowNum > 94) {
                //推送
                List<String> devIds = generalDeviceInfoClient.deptGetRunDev(user.getDeptId()).getData();
                OnlineRateParam top=new OnlineRateParam();
                top.setIds(devIds);
                top.setType(1);
                top.setStartTime(DateUtil.beginOfDay(DateUtil.parse(topMsgPO.getTime())).toString());
                top.setEndTime(DateUtil.endOfDay(DateUtil.parse(topMsgPO.getTime())).toString());
                List<TopMsgPO> data = generalDeviceInfoClient.getTopMsgInfoByIds(top).getData();
                String title = time + "终端异常共" + data.size()+ "台";
                String content = "异常情况：" + (StringUtils.isEmpty(alarmNum) ? "" : "终端告警：" + alarmNum + "次  ") + (StringUtils.isEmpty(comOutNum) ? "" : "通讯中断：" + Integer.valueOf(comOutNum) + "次  ") + (StringUtils.isEmpty(flowNum) ? "" : "终端流量：" + Float.valueOf(flowNum) + "%");
                sendMsg(user.getDevCode(), title, content, "3");
            }
        }
    }

    /**
     * 执行推送保存消息操作
     *
     * @param eventDetail 暂降事件
     * @param appUser     用户信息
     * @param devCode     手机唯一标识
     */
    private void pushEventInfo(RmpEventDetailPO eventDetail, User appUser, String devCode, int phonePushFlag) {
        //先根据用户获取推送策略
        AppInfoSet appInfoSet = appInfoSetService.getById(appUser.getId());
        if (ObjectUtil.isNotNull(appInfoSet)) {
            AppEventMsg eventMsg = new AppEventMsg();
            eventMsg.setEventdetailIndex(eventDetail.getEventId());
            eventMsg.setTimeID(eventDetail.getStartTime());
            eventMsg.setUserIndex(appUser.getId());
            eventMsg.setState(0);
            //执行保存消息记录操作
            appEventMsgService.save(eventMsg);
            if (appInfoSet.getEventInfo() == 1 && StrUtil.isNotBlank(devCode)) {
                //推送
                String content = "发生时刻：";
                //获取监测点信息
                List<LineDetailVO.Detail> lines = lineFeignClient.getLineDetailByIds(Arrays.asList(eventDetail.getLineId())).getData();
                if (CollUtil.isNotEmpty(lines)) {
                    LineDetailVO.Detail line = lines.get(0);
                    String time = LocalDateTimeUtil.format(eventDetail.getStartTime(), DatePattern.NORM_DATETIME_MS_PATTERN);
                    //暂降幅值
                    Float amplitude = PubUtils.floatRound(2, eventDetail.getFeatureAmplitude().floatValue() * 100);
                    //持续时间
                    Float duration = PubUtils.floatRound(2, eventDetail.getDuration().floatValue());
                    content = content + time + ",暂降幅值：" + amplitude + "%," + "持续时间：" + duration + "s。";
                    //todo 推送消息地址
                    sendMsg(devCode, line.getLineName() + "监测点发生暂态事件", content, "1");
                    //查询主账户是否开启短信通知 根据监测点ID找到部门找到用户
                    if (phonePushFlag == 0) {
                        //添加策略，判断当前该事件是否需要短信推送
                        boolean isPush = judgeEventNeedPush(eventDetail, line);
                        if (isPush) {
                            String message = "{\"line\":\"" + line.getLineName() + "\",\"time\":\"" + time + "\",\"ms\":\"" + eventDetail.getFirstMs() + "\",\"eventvalue\":\"" + amplitude + "\",\"persisttime\":\"" + duration + "\"}";
//                            smsUtil.sendSms(appUser.getPhone(), smsUtil.getMessageTemplate("8"), message);
                        }
                    }
                }
            }
        }

    }

    /***
     * 1、监测点等级：极重要----则全部发送；
     * 2、监测点等级：重要----一天内最多通过短信发送10条暂降事件；超过的则暂降小等于80的才发送；
     * 3、监测点等级：普通----一天内最多通过短信发送3条暂降事件；超过的则暂降小等于80的才发送；
     * 4、监测点等级：不重要----一天内最多通过短信发送1条暂降事件；超过的则暂降小等于80的才发送；
     * @author hongawen
     * @date 2023/7/31 10:15
     * @param eventDetail 暂降信息
     * @param lineIndex 监测点索引
     * @return boolean
     */
    private boolean judgeEventNeedPush(RmpEventDetailPO eventDetail, LineDetailVO.Detail lineIndex) {
        boolean pushFlag = true;
        String valueByKey = redisUtil.getStringByKey(RedisDB.ONE_DAY_QUERY, lineIndex.getLineId());
        if (StrUtil.isBlank(valueByKey)) {
            //为空，则最近24小时内没有发生暂降推送
            redisUtil.saveByKeyWithExpire(RedisDB.ONE_DAY_QUERY, lineIndex.getLineId(), "1", RedisDB.ONE_DAY_TIME);
        } else {
            //不为空，根据监测点重要程度来区分次数是否达到上限
            String lineGrade = lineIndex.getLineGrade();
            if (StrUtil.isBlank(lineGrade)) {
                lineGrade = "不重要";
            }
            if (eventDetail.getFeatureAmplitude() > 0.80f) {
                int times = Integer.parseInt(valueByKey);
                switch (lineGrade) {
                    case "重要":
                        if (times >= 10) {
                            pushFlag = false;
                        }
                        break;
                    case "普通":
                        if (times >= 3) {
                            pushFlag = false;
                        }
                        break;
                    case "不重要":
                        if (times >= 1) {
                            pushFlag = false;
                        }
                        break;
                    default:
                        break;
                }
                if (pushFlag) {
                    times++;
                    long ttl = redisUtil.getExpire(RedisDB.ONE_DAY_QUERY, String.valueOf(lineIndex));
                    redisUtil.saveByKeyWithExpire(RedisDB.ONE_DAY_QUERY, String.valueOf(lineIndex), String.valueOf(times), (int) ttl);
                }
            }
        }
        return pushFlag;
    }


    /**
     * 无人关注的监测点出现暂降消息处理
     *
     * @param eventDetailIndex 暂降索引
     * @param lineId           监测点索引
     */
    private void noUserFocus(String eventDetailIndex, String lineId) {
        //进行日志保存
        LogInfoDTO logInfoDTO = new LogInfoDTO();
        logInfoDTO.setLoginName(RequestUtil.getLoginName());
        logInfoDTO.setUserName(RequestUtil.getUserNickname());
        logInfoDTO.setIp(RequestUtil.getRealIp());
        logInfoDTO.setOperate(lineId + "的暂降消息" + eventDetailIndex + "无人监听");
        logInfoDTO.setOperateType("暂降推送");
        logInfoDTO.setResult(1);
        logInfoDTO.setLevel(1);
        logInfoDTO.setType(0);
        logInfoDTO.setServiceName("app-cloud");
        logInfoDTO.setUserIndex(RequestUtil.getUserIndex());
        userLogFeignClient.addUserLog(logInfoDTO);
        //抛出异常，返回调用者
        throw new BusinessException(UserCodeEnum.NO_USER_FOCUS.getMsg());
    }

    /**
     * 推送消息
     *
     * @param cid                 手机唯一标识
     * @param title               消息头
     * @param content             消息内容
     * @param transmissionContent 消息类别
     */
    private static void sendMsg(String cid, String title, String content, String transmissionContent) {
        String result;
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("cid", cid);
            jsonObject.put("title", title);
            jsonObject.put("content", content);
            jsonObject.put("transmissionContent", transmissionContent);
            result = null;
            JSONObject resultJson = JSONObject.fromObject(result);
            int resultCode = resultJson.getInt("returnCode");
            if (resultCode != 0) {
                log.error("推送消息的标题：{},失败，返回体为：{}", title, result);
                throw new AccountException(UserCodeEnum.STEADY_MSG_FAIL.getMsg());
            }
            log.error("推送消息的标题：{}，结果：{}", title, result);
        } catch (Exception e) {
            log.error("推送消息发生异常，异常是" + e.getMessage());
        }
    }
}
