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

import com.github.jfcloud.influxdb.util.InfluxDBDateFormatter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarmUser;
import vip.xiaonuo.coldchain.core.alarm.bean.SensorThreshold;
import vip.xiaonuo.coldchain.core.alarm.config.ColdChainAlarmMessageProperties;
import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
import vip.xiaonuo.coldchain.core.alarm.offline.DeviceOfflineDetectionService;
import vip.xiaonuo.coldchain.core.alarm.service.threshold.SensorThresholdService;
import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
import vip.xiaonuo.coldchain.core.event.SensorAlarmEvent;
import vip.xiaonuo.coldchain.modular.monitortargetregion.entity.MonitorTargetRegion;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@Component
@RequiredArgsConstructor
@Slf4j
public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
    // 定义一个日期格式化器，用于将时间格式化成可读的字符串
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private final SensorThresholdService thresholdService;
    private final ColdChainAlarmMessageProperties alarmMessageProperties;
    private final ApplicationEventPublisher applicationEventPublisher;

    private final DeviceOfflineDetectionService deviceOfflineDetectionService;

    @Override
    public boolean checkAlarm(SensorData sensorData) {
        if (sensorData == null) {
            throw new IllegalArgumentException("传感器数据不能为空！");
        }
        //记录数据报送时间
        deviceOfflineDetectionService.reportDeviceTime(sensorData.getDeviceId(), sensorData.getRoads());
        // 获取传感器阈值配置
        SensorThreshold threshold = thresholdService.getThresholdBySensorId(sensorData.getDeviceId(), sensorData.getRoads());
        if (threshold == null) {
            log.warn("没有找到设备编号: {} 的设置阈值配置,跳过预警", sensorData.getDeviceId());
            return false;
        }
        MonitorTargetRegion monitorTargetRegion = threshold.getMonitorTargetRegion();
        // 检查传感器数据并触发报警
        boolean alarmTriggered = false;
        if (noNull(sensorData.getTemperature())) {
            alarmTriggered = checkThreshold(sensorData.getTemperature(), threshold.getTemperatureUp(), threshold.getTemperatureDown(), "温度", monitorTargetRegion);
        }
        if (noNull(sensorData.getHumidity())) {
            alarmTriggered |= checkThreshold(sensorData.getHumidity(), threshold.getHumidityUp(), threshold.getHumidityDown(), "湿度", monitorTargetRegion);
        }
        if (noNull(sensorData.getCo2())) {
            alarmTriggered |= checkThreshold(sensorData.getCo2(), threshold.getCo2Up(), threshold.getCo2Down(), "二氧化碳", monitorTargetRegion);
        }
        if (noNull(sensorData.getBattery())) {
            alarmTriggered |= checkThreshold(sensorData.getBattery(), null, threshold.getBatteryDown(), "电量", monitorTargetRegion);
        }
        return alarmTriggered;
    }

    /**
     * 检查阈值并触发报警
     *
     * @param value          传感器数据的值
     * @param upperThreshold 阈值上限
     * @param lowerThreshold 阈值下限
     * @param type           数据类型（温度、湿度、二氧化碳）
     * @return 是否触发报警
     */
    private boolean checkThreshold(Float value, Float upperThreshold, Float lowerThreshold, String type, MonitorTargetRegion monitorTargetRegion) {
        boolean alarmTriggered = false;
        String time = DATE_FORMAT.format(new Date()); // 获取当前时间
        String unit = getUnit(type);
        if (noNull(upperThreshold) && value > upperThreshold) {
            // 超过上限，触发超标报警
            publishAlarm(type + "超标", value, unit, time, upperThreshold, monitorTargetRegion);
            alarmTriggered = true;
        } else if (noNull(lowerThreshold) && value < lowerThreshold) {
            // 低于下限，触发低于阈值报警
            publishAlarm(type + "过低", value, unit, time, lowerThreshold, monitorTargetRegion);
            alarmTriggered = true;
        }
        return alarmTriggered;
    }


    /**
     * 发布报警事件
     *
     * @param alarmType 报警类型（例如 温度超标、湿度过低等）
     * @param value     传感器数据值
     * @param unit      传感器数据单位
     * @param time      时间戳
     */
    private void publishAlarm(String alarmType, Float value, String unit, String time, float threshold, MonitorTargetRegion monitorTargetRegion) {
        String monitorTargetId = monitorTargetRegion.getMonitorTargetId();
        Integer sensorRoute = monitorTargetRegion.getSensorRoute();
        String  sensorCode = monitorTargetRegion.getSensorCode();
        String deviceName = monitorTargetRegion.getName();
        String deviceId = monitorTargetRegion.getId();
        String alarmMessage = getAlarmMessage(alarmType, value, unit, deviceName, time, threshold);
        SensorAlarm sensorAlarm = new SensorAlarm();
        sensorAlarm.setAlarmType(alarmType);  // 设置报警类型（例如 温度超标、湿度过低等）
        sensorAlarm.setValue(value);  // 设置传感器值
        sensorAlarm.setAlarmTime(InfluxDBDateFormatter.now(new Date()));  // 设置单位（例如 °C, %, ppm）
        sensorAlarm.setSource(deviceName);  // 设置设备名称
        sensorAlarm.setDeviceName(deviceName);  // 设置设备名称
        sensorAlarm.setDeviceId(deviceId);  // 设置设备名称
        sensorAlarm.setPriority("中");  // 设置设备名称
        sensorAlarm.setStatus("未处理");  // 设置设备名称
        sensorAlarm.setAlarmTime(time);  // 设置报警时间
        sensorAlarm.setMessage(alarmMessage);  // 设置报警消息
        sensorAlarm.setThreshold(threshold);  // 设置预警值
        sensorAlarm.setMonitorTargetId(monitorTargetId);
        sensorAlarm.setSensorRoute(sensorRoute);
        sensorAlarm.setSensorCode(sensorCode);
        sensorAlarm.setCreateUser(monitorTargetRegion.getCreateUser());
        List<SensorAlarmUser> alarmUsers = monitorTargetRegion.getAlarmUsers();
        sensorAlarm.setAlarmUsers(alarmUsers);
        sensorAlarm.setThreshold(threshold);
        sensorAlarm.setType(SensorAlarmType.DATA_ALARM.getDeviceCode());
        // 设置报警人机构 所属用户和机构
        sensorAlarm.setCreateUser(monitorTargetRegion.getCreateUser());
        sensorAlarm.setCreateOrg(monitorTargetRegion.getCreateOrg());
        // 添加房间字段
        sensorAlarm.setRoomName(monitorTargetRegion.getRoomName());
        log.warn("触发报警: 类型: {},详细报警内容 : {}", alarmType, alarmMessage);
        // 发布报警事件
        applicationEventPublisher.publishEvent(new SensorAlarmEvent(this, sensorAlarm));
    }

    /**
     * 获取报警消息模板并替换占位符
     *
     * @param alarmType  报警类型（例如 温度超标、湿度过低等）
     * @param value      传感器数据值
     * @param unit       传感器数据单位
     * @param deviceName 设备名称
     * @param time       时间戳
     * @return 格式化后的报警消息
     */
    private String getAlarmMessage(String alarmType, Float value, String unit, String deviceName, String time, float threshold) {
        String messageTemplate = "";
        // 根据报警类型获取对应的消息模板
        switch (alarmType) {
            case "温度超标":
                messageTemplate = alarmMessageProperties.getTemperatureOverLimit();
                break;
            case "温度过低":
                messageTemplate = alarmMessageProperties.getTemperatureBelowLimit();
                break;
            case "湿度超标":
                messageTemplate = alarmMessageProperties.getHumidityOverLimit();
                break;
            case "湿度过低":
                messageTemplate = alarmMessageProperties.getHumidityBelowLimit();
                break;
            case "二氧化碳超标":
                messageTemplate = alarmMessageProperties.getCo2OverLimit();
                break;
            case "二氧化碳过低":
                messageTemplate = alarmMessageProperties.getCo2BelowLimit();
                break;
            default:
                messageTemplate = "{alarmType}: 当前值：{value} {unit}";
                break;
        }
        // 替换模板中的占位符
        String replace = messageTemplate.replace("{value}", String.format("%.2f", value)).replace("{unit}", unit).replace("{alarmType}", alarmType).replace("{time}", time).replace("{deviceName}", deviceName).replace("{threshold}", String.format("%.2f", threshold));
        return replace;
    }

    private String getUnit(String sensorType) {
        return switch (sensorType) {
            case "温度" -> "°C";
            case "湿度" -> "%";
            case "二氧化碳" -> "ppm";
            default -> "";
        };
    }

    private boolean noNull(Float value) {
        return value != null && value != 0.0;
    }
}
