package com.tuoheng.admin.service.mqttService.consumer.topicHandle.alarm;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tuoheng.admin.enums.AlarmTypeEnum;
import com.tuoheng.admin.enums.MQTTTopicEnum;
import com.tuoheng.admin.mapper.AirportMapper;
import com.tuoheng.admin.mapper.AlarmLogMapper;
import com.tuoheng.admin.pojo.entity.Airport;
import com.tuoheng.admin.pojo.entity.AlarmLog;
import com.tuoheng.admin.pojo.entity.Bnconnect;
import com.tuoheng.admin.service.bnconnect.IBnconnectService;
import com.tuoheng.admin.service.mqttpush.IMqttPushService;
import com.tuoheng.admin.service.mqttService.HttpURLConnectionUtil;
import com.tuoheng.admin.service.mqttService.consumer.topicHandle.ITopicHandleService;
import com.tuoheng.admin.utils.SpringUtil;
import com.tuoheng.common.enums.MarkStatusEnum;
import com.tuoheng.common.utils.DateUtils;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Author: 吴彬
 * @CreateTime: 2023-06-12  10:28
 * @Description: 告警记录处理 服务实现类
 * @Version: 1.0
 */
@Service
@Slf4j
public class AlarmTopicHandleService implements ITopicHandleService {

    @Resource
    private AlarmLogMapper alarmLogMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * DSP 告警服务URI
     */
    private final static String DSP_ALARM_URI = "/alarm/alarmData";

    /**
     * DSP 平台编码
     */
    private final static String DSP_PLATFORMCODE = "001";

    /**
     * DSP 告警模板
     */
    private final static String DSP_ALARM_TEMPLATE = "您好，您所管辖的机场：${name}，正在发生告警，告警内容是：${msg}，请及时处理！";

    /**
     * 机场日志记录topic
     */
    private static final String topic = MQTTTopicEnum.TOPIC_POST_WTH.getTopic();


    @Override
    public String getTopic() {
        return topic;
    }

    /**
     * 告警日志处理
     *
     * @param message MQTT message
     * @param edgId   设备ID
     */
    @Override
    public void topicHandle(MqttMessage message, String edgId) {
        /**
         * 常规日志：
         *  打印日志即可
         * 错误日志：
         *  记录数据库
         * 紧急日志：
         *  1、记录告警日志
         *  2、调用DSP接口上报告警数据
         *  3、发送MQTT消息告警已处理
         *  4、DSP调用成功更新告警记录为已处理
         */
        JSONObject jsonObject = (JSONObject) JSONObject.parse(message.getPayload());

        if (ObjectUtil.isEmpty(jsonObject.get("type"))) {
            log.error("告警日志类型为空，消息无需处理！");
            return;
        }

        if (AlarmTypeEnum.ALARM_LOG.getType().equals(jsonObject.get("type").toString())) {
            log.info("常规日志无需处理！");
            log.info("常规日志内容：{}", jsonObject);
        }

        //获取机场信息
        AirportMapper airportMapper = SpringUtil.getBean(AirportMapper.class);
        IBnconnectService bnconnectService = SpringUtil.getBean(IBnconnectService.class);
        List<Airport> airports = airportMapper.selectList(new LambdaQueryWrapper<Airport>()
                .eq(Airport::getMark, MarkStatusEnum.VALID.getCode())
                .eq(Airport::getEdgeId, edgId));
        if (CollectionUtils.isEmpty(airports)) {
            log.error("控制板ID:{},对应机场信息不存在！", edgId);
            return;
        }
        Bnconnect bnconnect = bnconnectService.selectByCode("alarmDsp");

        String critical = jsonObject.get("critical") == null ? "" : jsonObject.get("critical").toString();
        String data = jsonObject.get("critical") == null ? "" : jsonObject.get("critical").toString();
        String time = jsonObject.get("timestamp") == null ? "0" : jsonObject.get("timestamp").toString();

        //记录告警日志
        AlarmLog alarmLog = new AlarmLog();
        alarmLog.setAirportId(airports.get(0).getId());
        alarmLog.setEdgeId(edgId);
        alarmLog.setCritical(critical);
        alarmLog.setData(data);
        alarmLog.setTimestamp(time);
        Date createDate = new Date(Long.valueOf(time) * 1000L);//注意硬件传过来的时间戳是10位的，故需要乘以1000
        alarmLog.setCreateTime(createDate);
        alarmLog.setUpdateTime(createDate);

        if (AlarmTypeEnum.ALARM_ERROR.getType().equals(jsonObject.get("type").toString())) {
            /**
             * 错误日志只记录数据库
             */
            alarmLog.setType(AlarmTypeEnum.ALARM_ERROR.getType());
            this.saveAlarmLog(alarmLog);
        } else if (AlarmTypeEnum.ALARM_CRITICAL.getType().equals(jsonObject.get("type").toString())) {
            if(ObjectUtil.isEmpty(jsonObject.get("critical"))){
                log.info("紧急告警内容为空，消息无需处理！");
                return;
            }
            /**
             * 告警日志记录数据库+上报DSP
             */
            IMqttPushService mqttService = SpringUtil.getBean(IMqttPushService.class);
            try {
                String airportName = airports.get(0).getName();
                alarmLog.setType(AlarmTypeEnum.ALARM_CRITICAL.getType());
                alarmLog.setResult(AlarmLog.HANDLE_NOT);
                Integer insertResult = this.saveAlarmLog(alarmLog);
                if (insertResult <= 0) {
                    log.error("异常告警数据：{}，记录入库异常：", time);
                    return;
                }
                log.info("异常告警数据：{}，记录入库成功！", time);
                //调用DSP，上报异常告警数据
                HttpURLConnectionUtil httpURLConnectionUtil = new HttpURLConnectionUtil();
                //dps请求地址
                String url = bnconnect.getApiUrl() + DSP_ALARM_URI;
                //请求参数
                List parm = new ArrayList();
                Map parmMap = new HashMap();
                parmMap.put("platformCode", DSP_PLATFORMCODE);
                Map parmMapTemplate = new HashMap();
                parmMapTemplate.put("name", airportName);
                parmMapTemplate.put("msg", critical);
                parmMap.put("alarmData", JSONObject.toJSONString(parmMapTemplate));
                parmMap.put("alarmTemplate", DSP_ALARM_TEMPLATE);
                parm.add(parmMap);
                String jsonparm = JSONObject.toJSONString(parm);
                log.info("请求地址{}，请求类型put，请求体{}", url, jsonparm);
                String dspResponse = httpURLConnectionUtil.doPut(url, jsonparm);
                log.info("请求返回值{}", dspResponse);
                if (StringUtils.isEmpty(dspResponse)) {
                    log.error("异常告警数据上报调用DSP返回结果为空！");
                    throw new RuntimeException("异常告警数据上报调用DSP返回结果为空！");
                } else {
                    JSONObject dspJSObject = JSONObject.parseObject(dspResponse);
                    if (ObjectUtil.isNotEmpty(dspJSObject) && JsonResult.SUCCESS == dspJSObject.getInteger("code")) {
                        //发送MQTT消息告警已处理
                        mqttService.alarmSend(edgId, AlarmLog.HANDLE_AGO, Long.parseLong(time));
                        log.info("告警数据：{}，控制面板ID:{}，告警处理已回复", time, edgId);
                        alarmLog.setResult(AlarmLog.HANDLE_AGO);
                        alarmLog.setUpdateTime(DateUtils.now());
                        //更新告警记录已处理
                        alarmLogMapper.updateById(alarmLog);
                    } else {
                        //请求返回失败
                        log.error("异常告警数据：{}，上报调用DSP异常，返回值：{}", time, dspJSObject);
                        throw new RuntimeException("异常告警数据上报调用DSP返回结果异常！");
                    }

                    try{
                        sendAlarmLog(airports.get(0).getCode(),airports.get(0),alarmLog);
                    }catch (Exception e){
                        log.error("发送告警日志：{}，到redis通道：{}，异常：{}",alarmLog,airports.get(0).getCode(),e);
                    }
                }
            } catch (Exception e) {
                log.error("告警数据：{}，处理异常，通知MQTT消息未处理", time, e);
                //发送MQTT消息告警未处理
                mqttService.alarmSend(edgId, AlarmLog.HANDLE_NOT, Long.parseLong(time));
            }
        }
    }

    /**
     * 记录告警日志
     *
     * @param alarmLog
     */
    private int saveAlarmLog(AlarmLog alarmLog) {
        return alarmLogMapper.insert(alarmLog);
    }

    /**
     * 发送告警日志到redis通道
     * @param deviceId  地面站ID
     * @param airport   机场信息
     * @param alarmLog  告警信息
     */
    private void sendAlarmLog(String deviceId,Airport airport,AlarmLog alarmLog){
        JSONObject jsonObject = new JSONObject();
        JSONObject alarmData = new JSONObject();
        alarmData.put("airportName",airport.getName());//机场名称
        if(alarmLog.getType() == AlarmTypeEnum.ALARM_CRITICAL.getType()){
            //告警通知为紧急是取critical字段，因为data字段是英文
            alarmData.put("alarmMsg", alarmLog.getCritical());//告警内容
        }else {
            alarmData.put("alarmMsg", alarmLog.getData());//告警内容
        }
        alarmData.put("alarmDate",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,alarmLog.getCreateTime()));//告警时间
        jsonObject.put("alarmData",alarmData);
        log.info("发送告警日志：{}，到redis通道：{}",jsonObject.toJSONString(),deviceId);
        redisTemplate.convertAndSend(deviceId, jsonObject.toJSONString());
    }
}
