package com.haha.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.constant.RedisConstants;
import com.haha.common.enums.DeviceAlertType;
import com.haha.entity.Device;
import com.haha.entity.DeviceAlertRecord;
import com.haha.entity.Shop;
import com.haha.mapper.DeviceAlertRecordMapper;
import com.haha.service.DeviceAlertService;
import com.haha.service.DeviceService;
import com.haha.service.ShopService;
import com.haha.service.config.DeviceAlertProperties;
import com.haha.service.notify.WeChatWorkNotifyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * 设备告警服务实现
 */
@Slf4j
@Service
public class DeviceAlertServiceImpl extends ServiceImpl<DeviceAlertRecordMapper, DeviceAlertRecord>
        implements DeviceAlertService {

    private static final String NOTIFY_CHANNEL = "WECHAT_WORK";
    private static final int NOTIFY_SUCCESS = 1;
    private static final int NOTIFY_FAIL = 2;
    private static final int ALERT_LEVEL_NORMAL = 1;
    private static final int ALERT_LEVEL_URGENT = 2;

    @Autowired
    private DeviceAlertRecordMapper deviceAlertRecordMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private ShopService shopService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private WeChatWorkNotifyService weChatWorkNotifyService;
    @Autowired
    private DeviceAlertProperties properties;

    @Override
    public void processOfflineAlert(String deviceId, String triggerSource) {
        try {
            if (!properties.isEnabled()) {
                log.debug("[设备告警] 告警功能已禁用，跳过离线告警处理 - deviceId: {}", deviceId);
                return;
            }

            if (isInCooldown(deviceId, DeviceAlertType.OFFLINE)) {
                log.debug("[设备告警] 设备离线告警处于冷却期，跳过 - deviceId: {}", deviceId);
                return;
            }

            // 查询设备信息
            Device device = deviceService.getDeviceBySn(deviceId);
            if (device == null) {
                log.warn("[设备告警] 设备不存在，跳过离线告警 - deviceId: {}", deviceId);
                return;
            }

            String deviceName = device.getName() != null ? device.getName() : deviceId;
            String shopName = getShopName(device.getShopId());
            LocalDateTime alertTime = LocalDateTime.now();

            // 构建告警记录
            DeviceAlertRecord record = new DeviceAlertRecord();
            record.setDeviceId(deviceId);
            record.setShopId(device.getShopId());
            record.setDeviceName(deviceName);
            record.setAlertType(DeviceAlertType.OFFLINE.getCode());
            record.setAlertLevel(ALERT_LEVEL_URGENT);
            record.setAlertContent(String.format("设备[%s](%s)离线，所属门店：%s，触发来源：%s",
                    deviceName, deviceId, shopName, triggerSource));
            record.setTriggerSource(triggerSource);
            record.setAlertTime(alertTime);
            record.setNotifyChannel(NOTIFY_CHANNEL);

            // 发送通知
            int notifyStatus = NOTIFY_FAIL;
            try {
                weChatWorkNotifyService.sendOfflineAlert(deviceId, deviceName, shopName, triggerSource, alertTime);
                notifyStatus = NOTIFY_SUCCESS;
                log.info("[设备告警] 离线告警通知发送成功 - deviceId: {}", deviceId);
            } catch (Exception e) {
                log.error("[设备告警] 离线告警通知发送失败 - deviceId: {}", deviceId, e);
            }

            record.setNotifyStatus(notifyStatus);
            this.save(record);

            // 设置冷却期
            setCooldown(deviceId, DeviceAlertType.OFFLINE);

            // 在Redis中标记设备为离线状态（用于恢复上线判断）
            String offlineKey = String.format(RedisConstants.DEVICE_LAST_ONLINE_KEY, deviceId);
            stringRedisTemplate.opsForValue().set(offlineKey, alertTime.toString());

            log.info("[设备告警] 离线告警处理完成 - deviceId: {}, notifyStatus: {}", deviceId, notifyStatus);
        } catch (Exception e) {
            log.error("[设备告警] 处理离线告警异常 - deviceId: {}", deviceId, e);
        }
    }

    @Override
    public void processWeakSignalAlert(String deviceId, Integer signalValue, String triggerSource) {
        try {
            if (!properties.isEnabled()) {
                log.debug("[设备告警] 告警功能已禁用，跳过信号弱告警处理 - deviceId: {}", deviceId);
                return;
            }

            if (signalValue == null || signalValue > properties.getWeakSignalThreshold()) {
                log.debug("[设备告警] 信号值正常，跳过 - deviceId: {}, signalValue: {}, threshold: {}",
                        deviceId, signalValue, properties.getWeakSignalThreshold());
                return;
            }

            if (isInCooldown(deviceId, DeviceAlertType.WEAK_SIGNAL)) {
                log.debug("[设备告警] 设备信号弱告警处于冷却期，跳过 - deviceId: {}", deviceId);
                return;
            }

            // 查询设备信息
            Device device = deviceService.getDeviceBySn(deviceId);
            if (device == null) {
                log.warn("[设备告警] 设备不存在，跳过信号弱告警 - deviceId: {}", deviceId);
                return;
            }

            String deviceName = device.getName() != null ? device.getName() : deviceId;
            String shopName = getShopName(device.getShopId());
            LocalDateTime alertTime = LocalDateTime.now();

            // 构建告警记录
            DeviceAlertRecord record = new DeviceAlertRecord();
            record.setDeviceId(deviceId);
            record.setShopId(device.getShopId());
            record.setDeviceName(deviceName);
            record.setAlertType(DeviceAlertType.WEAK_SIGNAL.getCode());
            record.setAlertLevel(ALERT_LEVEL_NORMAL);
            record.setAlertContent(String.format("设备[%s](%s)信号弱，信号值：%d，所属门店：%s",
                    deviceName, deviceId, signalValue, shopName));
            record.setSignalValue(signalValue);
            record.setTriggerSource(triggerSource);
            record.setAlertTime(alertTime);
            record.setNotifyChannel(NOTIFY_CHANNEL);

            // 发送通知
            int notifyStatus = NOTIFY_FAIL;
            try {
                weChatWorkNotifyService.sendWeakSignalAlert(deviceId, deviceName, shopName, signalValue, alertTime);
                notifyStatus = NOTIFY_SUCCESS;
                log.info("[设备告警] 信号弱告警通知发送成功 - deviceId: {}, signalValue: {}", deviceId, signalValue);
            } catch (Exception e) {
                log.error("[设备告警] 信号弱告警通知发送失败 - deviceId: {}", deviceId, e);
            }

            record.setNotifyStatus(notifyStatus);
            this.save(record);

            // 设置冷却期
            setCooldown(deviceId, DeviceAlertType.WEAK_SIGNAL);

            log.info("[设备告警] 信号弱告警处理完成 - deviceId: {}, signalValue: {}, notifyStatus: {}",
                    deviceId, signalValue, notifyStatus);
        } catch (Exception e) {
            log.error("[设备告警] 处理信号弱告警异常 - deviceId: {}", deviceId, e);
        }
    }

    @Override
    public void processBackOnlineNotify(String deviceId) {
        try {
            if (!properties.isEnabled()) {
                log.debug("[设备告警] 告警功能已禁用，跳过恢复上线通知 - deviceId: {}", deviceId);
                return;
            }

            // 检查Redis中该设备是否有离线标记
            String offlineKey = String.format(RedisConstants.DEVICE_LAST_ONLINE_KEY, deviceId);
            Boolean hasOfflineMark = stringRedisTemplate.hasKey(offlineKey);
            if (!Boolean.TRUE.equals(hasOfflineMark)) {
                // log.debug("[设备告警] 设备无离线标记，跳过恢复上线通知 - deviceId: {}", deviceId);
                return;
            }

            // 查询设备信息
            Device device = deviceService.getDeviceBySn(deviceId);
            if (device == null) {
                log.warn("[设备告警] 设备不存在，跳过恢复上线通知 - deviceId: {}", deviceId);
                return;
            }

            String deviceName = device.getName() != null ? device.getName() : deviceId;
            String shopName = getShopName(device.getShopId());
            LocalDateTime now = LocalDateTime.now();

            // 构建告警记录
            DeviceAlertRecord record = new DeviceAlertRecord();
            record.setDeviceId(deviceId);
            record.setShopId(device.getShopId());
            record.setDeviceName(deviceName);
            record.setAlertType(DeviceAlertType.BACK_ONLINE.getCode());
            record.setAlertLevel(ALERT_LEVEL_NORMAL);
            record.setAlertContent(String.format("设备[%s](%s)已恢复上线，所属门店：%s", deviceName, deviceId, shopName));
            record.setTriggerSource("SYSTEM");
            record.setAlertTime(now);
            record.setNotifyChannel(NOTIFY_CHANNEL);

            // 发送通知
            int notifyStatus = NOTIFY_FAIL;
            try {
                weChatWorkNotifyService.sendBackOnlineNotify(deviceId, deviceName, shopName, now);
                notifyStatus = NOTIFY_SUCCESS;
                log.info("[设备告警] 恢复上线通知发送成功 - deviceId: {}", deviceId);
            } catch (Exception e) {
                log.error("[设备告警] 恢复上线通知发送失败 - deviceId: {}", deviceId, e);
            }

            record.setNotifyStatus(notifyStatus);
            this.save(record);

            // 删除Redis中的离线标记
            stringRedisTemplate.delete(offlineKey);

            // 删除该设备的离线告警冷却key（设备已恢复，下次再离线应立即告警）
            String cooldownKey = String.format(RedisConstants.DEVICE_ALERT_COOLDOWN_KEY,
                    deviceId, DeviceAlertType.OFFLINE.getCode());
            stringRedisTemplate.delete(cooldownKey);

            log.info("[设备告警] 恢复上线通知处理完成 - deviceId: {}, notifyStatus: {}", deviceId, notifyStatus);
        } catch (Exception e) {
            log.error("[设备告警] 处理恢复上线通知异常 - deviceId: {}", deviceId, e);
        }
    }

    /**
     * 判断设备告警是否在冷却期内
     */
    private boolean isInCooldown(String deviceId, DeviceAlertType alertType) {
        String key = String.format(RedisConstants.DEVICE_ALERT_COOLDOWN_KEY, deviceId, alertType.getCode());
        return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
    }

    /**
     * 设置设备告警冷却期
     */
    private void setCooldown(String deviceId, DeviceAlertType alertType) {
        String key = String.format(RedisConstants.DEVICE_ALERT_COOLDOWN_KEY, deviceId, alertType.getCode());
        stringRedisTemplate.opsForValue().set(key, "1", properties.getCooldownMinutes(), TimeUnit.MINUTES);
    }

    @Override
    public void processAbnormalOrderAlert(String deviceId, Long orderId, String alertContent) {
        try {
            if (!properties.isEnabled()) {
                log.debug("[设备告警] 告警功能已禁用，跳过异常订单告警 - deviceId: {}", deviceId);
                return;
            }

            // 查询设备信息
            Device device = deviceService.getDeviceBySn(deviceId);
            if (device == null) {
                log.warn("[设备告警] 设备不存在，跳过异常订单告警 - deviceId: {}", deviceId);
                return;
            }

            String deviceName = device.getName() != null ? device.getName() : deviceId;
            String shopName = getShopName(device.getShopId());
            LocalDateTime alertTime = LocalDateTime.now();

            // 构建告警记录
            DeviceAlertRecord record = new DeviceAlertRecord();
            record.setDeviceId(deviceId);
            record.setShopId(device.getShopId());
            record.setDeviceName(deviceName);
            record.setAlertType(DeviceAlertType.ABNORMAL_ORDER.getCode());
            record.setAlertLevel(ALERT_LEVEL_NORMAL); // 普通级别，管理员可在后台审核
            record.setAlertContent(String.format("订单ID:%d - %s，设备[%s](%s)，门店：%s",
                    orderId, alertContent, deviceName, deviceId, shopName));
            record.setTriggerSource("SYSTEM");
            record.setAlertTime(alertTime);

            this.save(record);
            log.info("[设备告警] 异常订单告警已记录 - deviceId: {}, orderId: {}, content: {}",
                    deviceId, orderId, alertContent);

        } catch (Exception e) {
            log.error("[设备告警] 处理异常订单告警异常 - deviceId: {}, orderId: {}", deviceId, orderId, e);
        }
    }

    /**
     * 获取门店名称
     */
    private String getShopName(Long shopId) {
        if (shopId == null) {
            return "未关联门店";
        }
        try {
            Shop shop = shopService.getById(shopId);
            return shop != null ? shop.getName() : "未知门店";
        } catch (Exception e) {
            log.warn("[设备告警] 查询门店信息失败 - shopId: {}", shopId, e);
            return "未知门店";
        }
    }
}
