package vip.xiaonuo.coldchain.core.alarm.service.messagepush;

import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import vip.xiaonuo.coldchain.core.alarm.bean.NotificationChannel;
import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarmUser;
import vip.xiaonuo.coldchain.core.alarm.mapper.SensorAlarmMapper;
import vip.xiaonuo.coldchain.core.config.JfcloudColdChainConstants;

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

/**
 * @author jackzhou
 * @version 1.0
 * @project jfcloud-coldchain
 * @description
 * @date 2024/11/27 16:09:54
 */
@Service
@Slf4j
@RequiredArgsConstructor
@Primary
public class RedisSensorAlarmMessagePushService {
    private final Map<String, MessagePushService> pushServices;
    private final SensorAlarmMapper sensorAlarmMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    @Async("coldChainAsyncTask")
    public void pushAlarmMessage(SensorAlarm alarm) {
        String deviceID = alarm.getDeviceId();
        String alarmType = alarm.getAlarmType();
        Map<String, SensorAlarmUser> users = Optional.ofNullable(alarm.getAlarmUsers()).orElse(Collections.emptyList()) // 如果为 null 则返回空集合
                .stream().filter(Objects::nonNull) // 过滤掉 null 的用户
                .filter(user -> StrUtil.isNotBlank(user.getOpenId())) // 过滤掉 openId 为空的用户
                .collect(Collectors.toMap(SensorAlarmUser::getOpenId, // key 是 openId
                        user -> user // value 是当前的 AlarmUser 对象
                ));
        if (users.isEmpty()) {
            log.info("No user found for alarm {}", alarm);
            return;
        }
        List<SensorAlarmUser> alarmUsers = users.values().stream().toList();
        for (String openid : users.keySet()) {
            SensorAlarmUser user = users.get(openid);
            if (hasExceededPushLimit(openid, deviceID, alarmType)) {
                log.info("用户 {} 对设备 {} 的告警类型 {} \n在过去{}分钟内推送次数超过限制，跳过推送", openid, deviceID, alarmType, JfcloudColdChainConstants.MESS_PUSH_TIME_WINDOW / 60 / 1000);
                continue;
            }
            // 只对当前人发送预警消息
            alarm.setAlarmUsers(List.of(user));
            for (NotificationChannel channel : alarm.getNotificationChannel()) {
                MessagePushService pushService = pushServices.get(channel.name());
                if (pushService != null) {
                    try {
                        boolean b = pushService.sendAlarmMessage(alarm);
                        alarm.setNotified(b);
                        log.info("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Alarm message sent successfully {}，{}", channel.name(), alarm);
                    } catch (Exception e) {
                        log.error("推送消息失败，渠道: {}，错误: {}", channel.getChannelName(), e.getMessage());
                    }
                } else {
                    log.warn("不支持的通知渠道: {}", channel.getChannelName());
                }
            }
            recordPushTime(openid, deviceID, alarmType);
        }
        // 还原这条消息的发送所有人
        alarm.setAlarmUsers(alarmUsers);
        saveAlarmToDatabase(alarm);
    }

    private boolean hasExceededPushLimit(String openid, String deviceID, String alarmType) {
        String key = generatePushHistoryKey(openid, deviceID, alarmType);
        List<Object> pushTimes = redisTemplate.opsForList().range(key, 0, -1);
        if (pushTimes == null || pushTimes.isEmpty()) {
            return false;
        }
        long currentTime = System.currentTimeMillis();
        pushTimes.removeIf(time -> currentTime - (Long) time > JfcloudColdChainConstants.MESS_PUSH_TIME_WINDOW);
        return pushTimes.size() >= JfcloudColdChainConstants.MESS_PUSH_MAX_PUSH_COUNT;
    }

    private void recordPushTime(String openid, String deviceID, String alarmType) {
        String key = generatePushHistoryKey(openid, deviceID, alarmType);
        long currentTime = System.currentTimeMillis();
        redisTemplate.opsForList().rightPush(key, currentTime);
        redisTemplate.opsForList().trim(key, -JfcloudColdChainConstants.MESS_PUSH_MAX_PUSH_COUNT, -1);
    }

    private void saveAlarmToDatabase(SensorAlarm alarm) {
        try {
            sensorAlarmMapper.insert(alarm);
        } catch (Exception e) {
            log.error("保存告警信息到数据库失败: {}", e.getMessage());
        }
    }

    private String generatePushHistoryKey(String openid, String deviceID, String alarmType) {
        return JfcloudColdChainConstants.REDIS_PUSH_HISTORY_KEY_PREFIX + ":" + openid + ":" + deviceID + ":" + alarmType;
    }
}
