package com.cpp.web.service.alarm;

import ch.qos.logback.classic.Logger;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cpp.common.utils.spring.SpringUtils;
import com.cpp.web.domain.alarm.AbnormalAlarm;
import com.cpp.web.domain.alarm.AlarmConf;
import com.cpp.web.domain.enums.AlarmEnum;
import com.cpp.web.domain.enums.DataSourcesEnum;
import com.cpp.web.utils.LogUtil;
import lombok.Data;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 * 告警日志类
 */
public class AlarmLog {

    //实时告警map
    private Map<String, AlarmDto> alarmDtoMap = new ConcurrentHashMap<>();

    private Logger logger = new AppenderFactory().getAppender();

    public static final AlarmLog getInstance() {
        return LazyHolder.INSTANCE;
    }

    //一个告警过滤的缓存map
    private Map<String, List<AlarmConf>> stationAlarmConfListMap = new ConcurrentHashMap<>();

    private static class LazyHolder {
        private static final AlarmLog INSTANCE = new AlarmLog();
    }

    /**
     * 告警日志打印+存储
     *
     * @param alarmSource 数据来源
     * @param alarmType   告警类型
     * @param info        告警信息
     * @param stationCode 场站编号
     */
    public void info(DataSourcesEnum alarmSource, AlarmEnum alarmType, String info, String stationCode) {
        List<AlarmConf> alarmConfs = new ArrayList<>();

        if (stationAlarmConfListMap.containsKey(stationCode)) {
            alarmConfs.addAll(stationAlarmConfListMap.get(stationCode));
        }
        if (stationAlarmConfListMap.containsKey("all")) {
            alarmConfs.addAll(stationAlarmConfListMap.get("all"));
        }
        Integer status = 0;
        if (alarmConfs != null && alarmConfs.stream().anyMatch(a -> a.getType().equals(1) ? a.getKeyword().equals(info) : info.contains(a.getKeyword()))) {
            status = 1;
        }

        String key = alarmSource.getCode() + "_" + alarmType.getCode() + "_" + info + "_" + stationCode;
        if (alarmDtoMap.containsKey(key)) {
            alarmDtoMap.get(key).setUpdateTime(new Date());
        } else {
            AbnormalAlarm abnormalAlarm = new AbnormalAlarm(alarmSource, alarmType, info, stationCode);
            abnormalAlarm.setStatus(status);
            SpringUtils.getBean(AbnormalAlarmService.class).save(abnormalAlarm);
            AlarmDto alarmDto = new AlarmDto(abnormalAlarm, new Date());
            alarmDtoMap.put(key, alarmDto);
        }

        logger.info(LogUtil.format("【场站编号：{}】，【业务类型：{}-{}】，【告警内容：{}】", stationCode, alarmSource.getMessage(), alarmType.getMessage(), info));

    }


    /**
     * 告警数据传输对象
     */
    @Data
    public class AlarmDto {
        private AbnormalAlarm abnormalAlarm;

        private Date updateTime;

        public AlarmDto(AbnormalAlarm abnormalAlarm, Date updateTime) {
            this.abnormalAlarm = abnormalAlarm;
            this.updateTime = updateTime;
        }
    }


    /**
     * 定时清理
     */
    public void eliminate() {
        List<String> keys = new ArrayList<>();
        List<AbnormalAlarm> abnormalAlarms = new ArrayList<>();

        //告警时效20分钟，20分钟内无重复告警将结束实时告警
        Date date = new Date(System.currentTimeMillis() - 1200000L);
        for (Map.Entry<String, AlarmDto> stringAlarmDtoEntry : alarmDtoMap.entrySet()) {
            AlarmDto alarmDto = stringAlarmDtoEntry.getValue();
            if (alarmDto.getUpdateTime().before(date)) {
                keys.add(stringAlarmDtoEntry.getKey());
                AbnormalAlarm abnormalAlarm = alarmDto.getAbnormalAlarm();
                abnormalAlarm.setEndTime(alarmDto.getUpdateTime());
                abnormalAlarms.add(abnormalAlarm);
            }
        }

        if (keys.size() > 0) {
            keys.forEach(k -> alarmDtoMap.remove(k));
            SpringUtils.getBean(AbnormalAlarmService.class).saveOrUpdateBatch(abnormalAlarms);
        }
    }


    /**
     * 将告警的常用信息装载缓存map
     */
    public void initMap() {
        List<AbnormalAlarm> abnormalAlarms = SpringUtils.getBean(AbnormalAlarmService.class).list(Wrappers.lambdaQuery(AbnormalAlarm.class).select().isNull(AbnormalAlarm::getEndTime));
        for (AbnormalAlarm abnormalAlarm : abnormalAlarms) {
            String key = abnormalAlarm.getAlarmSource().getCode() + "_" + abnormalAlarm.getAlarmType().getCode() + "_" + abnormalAlarm.getMsg() + "_" + abnormalAlarm.getStationCode();
            alarmDtoMap.put(key, new AlarmDto(abnormalAlarm, new Date()));
        }
        List<AlarmConf> alarmConfs = SpringUtils.getBean(AlarmConfService.class).list(Wrappers.lambdaQuery(AlarmConf.class).select().ge(AlarmConf::getExpireTime, new Date()));

        stationAlarmConfListMap = alarmConfs.stream().collect(Collectors.groupingBy(AlarmConf::getStationCode, Collectors.toList()));
    }


    /**
     * 更新缓存map
     *
     * @param alarmConf
     * @param b
     */
    public void updateStationAlarmConfListMap(AlarmConf alarmConf, Boolean b) {

        if (b) {
            //更新
            if (stationAlarmConfListMap.containsKey(alarmConf.getStationCode())) {
                List<AlarmConf> list = stationAlarmConfListMap.get(alarmConf.getStationCode());
                list.removeIf(s -> s.getId().equals(alarmConf.getId()));
                list.add(alarmConf);
            } else {
                List<AlarmConf> list = new ArrayList<>();
                list.add(alarmConf);
                stationAlarmConfListMap.put(alarmConf.getStationCode(), list);
            }

        } else {
            //删除
            if (stationAlarmConfListMap.containsKey(alarmConf.getStationCode())) {
                List<AlarmConf> list = stationAlarmConfListMap.get(alarmConf.getStationCode());
                list.removeIf(s -> s.getId().equals(alarmConf.getId()));
            }
        }
    }
}
