package com.zcxk.quartz.service;

import com.alibaba.fastjson.JSONObject;
import com.zcxk.client.UserCenterClient;
import com.zcxk.common.CalcUtil;
import com.zcxk.dao.alarm.DataAlarmAnalysisMapper;
import com.zcxk.dao.alarm.DataAlarmDetailMapper;
import com.zcxk.dao.alarm.DataAlarmManageMapper;
import com.zcxk.entity.Message;
import com.zcxk.entity.alarm.DataAlarmAnalysisEntity;
import com.zcxk.entity.alarm.DataAlarmDetailEntity;
import com.zcxk.entity.alarm.DataAlarmManageEntity;
import com.zcxk.vo.DataAlarmManageVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据报警处理
 * @author lihui
 * @date 2020-3-26
 */
@Slf4j
public abstract class AbstractDataAlarmJobService {

    @Resource
    protected DataAlarmDetailMapper dataAlarmDetailMapper;

    @Resource
    protected DataAlarmAnalysisMapper dataAlarmAnalysisMapper;

    @Resource
    protected DataAlarmManageMapper dataAlarmManageMapper;

    @Autowired
    protected UserCenterClient userCenterClient;

    @Resource(name = "messageRabbitTemplate")
    private AmqpTemplate messageRabbitTemplate;

    @Value("${receive.exchange.name}")
    private String receiveExchangeName;

    @Value("${dispath.routing.key}")
    private String dispathRoutingKey;

    /**
     * 挂起
     */
    protected static final int HANG_UP = 1;

    /***
     * 执行入口
     * @author lihui
     * @date 18:48 2021/6/1
     * @return void
     **/
    public void execute(){
        List<DataAlarmManageVo> manageVoList = this.listDataAlarmManage();
        if (CollectionUtils.isEmpty(manageVoList)) {
            log.info("获取数据报警管理参数数据为空");
            return;
        }
        DataAlarmManageEntity manageEntity;
        DataAlarmDetailEntity nowDetailEntity;
        Map<Long, DataAlarmDetailEntity> alarmDetailsDtoMap = getMapDataAlarmDetail(manageVoList);
        for (DataAlarmManageVo manageVo : manageVoList) {
            manageEntity = new DataAlarmManageEntity();
            BeanUtils.copyProperties(manageVo, manageEntity);
            nowDetailEntity = this.getAlarmValue(manageEntity);
            if (nowDetailEntity == null) {
                continue;
            }
            nowDetailEntity.setManageId(manageEntity.getId());
            boolean isAlarm = isAlarm(nowDetailEntity, manageEntity);
            // 必须先计算报警数据，才能执行保存数据报警分析操作，不然会丢失数据
            this.saveDataAlarmAnalysis(nowDetailEntity);
            // 计算出来属于报警，处理报警数据
            if (isAlarm) {
                handleAlarm(alarmDetailsDtoMap, manageVo, nowDetailEntity);
                continue;
            }
            // 存在报警信息，但已不报警，则更新为历史数据
            if (alarmDetailsDtoMap.containsKey(manageEntity.getId())){
                dataAlarmDetailMapper.updateHistoryData(alarmDetailsDtoMap.get(manageEntity.getId()).getId());
            }
        }
    }

    /***
     *  double转换BigDecimal
     * @author lihui
     * @date 11:48 2021/6/2
     * @param receivedValue :
     * @return java.math.BigDecimal
     **/
    protected BigDecimal toBigDecimal(Double receivedValue){
        return receivedValue == null ? null : new BigDecimal(receivedValue.toString());
    }

    /***
     * 保存报警数据
     * @author lihui
     * @date 11:09 2021/6/2
     * @param detailEntity :
     * @return void
     **/
    protected void saveDataAlarmDetail(DataAlarmDetailEntity detailEntity){
        detailEntity.setAlarmStartTime(new Date());
        detailEntity.setDateCreate(new Date());
        detailEntity.setStatus(1);
        dataAlarmDetailMapper.saveDataAlarmDetail(detailEntity);
    }


    /***
     * 保存分析数据详情
     * @author lihui
     * @date 9:43 2021/6/2
     * @param detailEntity :
     * @return void
     **/
    protected void saveDataAlarmAnalysis(DataAlarmDetailEntity detailEntity){
        DataAlarmAnalysisEntity analysisEntity = new DataAlarmAnalysisEntity();
        BeanUtils.copyProperties(detailEntity, analysisEntity);
        analysisEntity.setDateCreate(new Date());
        analysisEntity.setStatus(1);
        dataAlarmAnalysisMapper.saveDataAlarmAnalysis(analysisEntity);
    }

   /***
    * 数据存在，需要根据当前设置的计算规则和正在报警的计算规则是否一样
    * 一样：更新数据
    * 不一样：更新该条正在报警的数据为历史数据，并新增一条新计算规则的报警数据
    *  this.sendMessage(manageEntity);
    * @author lihui
    * @date 11:06 2021/6/2
    * @param alarmDetailsDtoMap : 现有报警数据
    * @param manageVo :          报警设置数据
    * @param nowDetailEntity :  当前报警数据
    * @return void
    **/
    private void handleAlarm(Map<Long, DataAlarmDetailEntity> alarmDetailsDtoMap, DataAlarmManageVo manageVo, DataAlarmDetailEntity nowDetailEntity){
        if (!alarmDetailsDtoMap.containsKey(manageVo.getId())){
            this.saveDataAlarmDetail(nowDetailEntity);
            this.sendMessage(manageVo);
            return;
        }
        DataAlarmDetailEntity dataAlarmDetailEntity =  alarmDetailsDtoMap.get(manageVo.getId());
        // 如果没有被挂起，就要发送消息提示
        if (dataAlarmDetailEntity.getIsHangup() != HANG_UP){
            this.sendMessage(manageVo);
        }
        // 检查计算规则是否有变更
        if (manageVo.getMd5Query().equals(dataAlarmDetailEntity.getMd5Query())) {
            dataAlarmDetailMapper.updateAlrarmData(dataAlarmDetailEntity);
            return;
        }
        // 规则有变更，数据更新为历史数据，再添加一条新的历史报警记录
        dataAlarmDetailMapper.updateHistoryData(dataAlarmDetailEntity.getId());
        this.saveDataAlarmDetail(nowDetailEntity);
    }


    /***
     * 获取报警数据
     * @author lihui
     * @date 10:58 2021/6/2
     * @param manageVoList :
     * @return java.util.Map<java.lang.Long,com.zcxk.entity.alarm.DataAlarmDetailEntity>
     **/
    private Map<Long, DataAlarmDetailEntity> getMapDataAlarmDetail(List<DataAlarmManageVo> manageVoList){
        List<Long> manageIds = manageVoList.stream().map(DataAlarmManageVo::getId).collect(Collectors.toList());
        List<DataAlarmDetailEntity> list = dataAlarmDetailMapper.listByManageId(manageIds);
        if (CollectionUtils.isEmpty(list)){
            return new HashMap<>();
        }
        return list.stream().collect(Collectors.toMap(DataAlarmDetailEntity::getManageId, a -> a,(k1, k2)->k1));
    }

    /***
     * 判断是否触发报警
     * @author lihui
     * @date 18:22 2021/6/1
     * @param dataAlarmDetailEntity :
     * @param dataAlarmManageEntity :
     * @return boolean
     **/
    private boolean isAlarm(DataAlarmDetailEntity dataAlarmDetailEntity, DataAlarmManageEntity dataAlarmManageEntity){
        BigDecimal resultValue = CalcUtil.operation(dataAlarmDetailEntity.getBeAlarmValue(), dataAlarmManageEntity.getComputeRules(),
                dataAlarmDetailEntity.getToAlarmValue());
        dataAlarmDetailEntity.setResultAlarmValue(resultValue);
        return CalcUtil.compareBySign(resultValue, dataAlarmManageEntity.getAlarmValue(), dataAlarmManageEntity.getAlarmRules());
    }

    /***
     * 消息发送
     * @author lihui
     * @date 18:46 2021/6/1
     * @param dataAlarmManageEntity :
     * @return void
     **/
    private void sendMessage(DataAlarmManageVo dataAlarmManageEntity){
        Message message = new Message();
        message.setStatus(1);
        message.setTenantId(dataAlarmManageEntity.getTenantId());
        message.setMessageId(UUID.randomUUID().toString());
        JSONObject jsonContent = new JSONObject();
        // ${场景名称}${设备名称}【${报警字段}】异常报警
        jsonContent.put("场景名称",dataAlarmManageEntity.getAlarmSettingRules());
        jsonContent.put("设备名称","");
        jsonContent.put("报警字段","");
        // 消息内容，如果需要动态使用，配合模板使用{key:value}
        message.setMessageContent(jsonContent.toJSONString());
        // 消息类型、模板id、渠道
        message.setMessageType(1);
        message.setMessageTemplateId(1);
        message.setChannel(0);
        Integer companyOrgId    = dataAlarmManageEntity.getCompanyOrgId();
        Integer departmentOrgId = dataAlarmManageEntity.getDeptOrgId();
        try{
            List<Integer> taskUsers = userCenterClient.findUserIdsByPermissonOrg(dataAlarmManageEntity.getTenantId(),companyOrgId,departmentOrgId);
            if (taskUsers == null) {
                return;
            }
            taskUsers.forEach(id -> {
                message.setUserId(id);
                this.send(message);
            });
        } catch (Exception e) {
            log.error ("推送报警消息失败:{}",e);
        }
    }

    private void send(Message message){
        log.debug("消息发送 exchange={}  routingkey={} 用户id={}",receiveExchangeName,dispathRoutingKey,message.getUserId());
        messageRabbitTemplate.convertAndSend(receiveExchangeName, dispathRoutingKey, JSONObject.toJSONString(message));
    }



    /***
     * 获取设置的报警参数
     * @author lihui
     * @date 18:15 2021/6/1
     * @return java.util.List<com.zcxk.entity.alarm.DataAlarmManageEntity>
     **/
    protected abstract List<DataAlarmManageVo> listDataAlarmManage();

    /***
     * 获取报警值
     * @author lihui
     * @date 11:47 2021/6/2
     * @param dataAlarmManageEntity : 报警设置参数
     * @return com.zcxk.entity.alarm.DataAlarmDetailEntity
     **/
    protected abstract DataAlarmDetailEntity getAlarmValue(DataAlarmManageEntity dataAlarmManageEntity);

}
