package vip.xiaonuo.coldchain.core.event;

import com.github.jfcloud.influxdb.service.JfcloudInfluxDBService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import vip.xiaonuo.coldchain.core.alarm.service.check.SensorAlarmChecker;
import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
import vip.xiaonuo.coldchain.core.config.JfcloudColdChainConstants;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@RequiredArgsConstructor
@Deprecated
public class SensorDataQueueEventListener {

    private final JfcloudInfluxDBService jfcloudInfluxDBService;
    private final SensorAlarmChecker sensorAlarmChecker;

    private final Queue<SensorData> bufferQueue = new ConcurrentLinkedQueue<>();
    private final Queue<SensorData> writeQueue = new ConcurrentLinkedQueue<>();

    // 使用 AtomicBoolean 来标记数据是否需要写入
    private final AtomicBoolean isWriteRequired = new AtomicBoolean(false);

    // 事件监听，处理传感器数据
    @EventListener
    public void handleSensorDataEvent(SensorDataEvent event) {
        SensorData sensorData = event.getSensorData();
        if (sensorData != null) {
            // 将数据添加到缓存队列
            addSensorDataToBufferQueue(sensorData);
            // 获取传感器的阈值范围并检查报警
            sensorAlarmChecker.checkAlarm(sensorData);
        }
    }

    // 将数据添加到缓存队列中
    public void addSensorDataToBufferQueue(SensorData sensorData) {
        bufferQueue.offer(sensorData);  // 将数据放入缓存队列

        // 如果缓存队列的大小超过了设定的阈值，立即进行数据转移和写入操作
        if (bufferQueue.size() >= JfcloudColdChainConstants.MAX_QUEUE_SIZE) {
            transferDataToWriteQueue();  // 将数据转移到写入队列
            writeDataToDatabaseAsync();  // 触发异步写入数据库
        }
    }

    // 将缓存队列的数据转移到写入队列
    private synchronized void transferDataToWriteQueue() {
        if (!bufferQueue.isEmpty()) {
            writeQueue.addAll(bufferQueue);
            bufferQueue.clear();  // 清空缓存队列
            log.debug("数据已从缓存队列转移到写入队列，当前写入队列大小: {}", writeQueue.size());
        }
    }

    // 异步写入数据到数据库
    @Async("coldChainAsyncTask")
    public void writeDataToDatabaseAsync() {
        if (!writeQueue.isEmpty()) {
            List<SensorData> dataList = new ArrayList<>(writeQueue);
            try {
                log.info("开始异步批量写入数据到 InfluxDB，数据量: {}", dataList.size());
                jfcloudInfluxDBService.writePojo(dataList);
                writeQueue.clear();  // 写入完成后清空写入队列
                log.info("数据成功写入 InfluxDB，队列已清空");
            } catch (Exception e) {
                log.error("写入数据到 InfluxDB 时出错: {}", e.getMessage(), e);
                // 如果写入失败，进行重试
                retryWriteDataToDatabase(dataList);
            }
        }
    }

    /**
     * 如果写入失败，进行重试
     */
    private void retryWriteDataToDatabase(List<SensorData> dataList) {
        int retries = JfcloudColdChainConstants.MAX_RETRIES;
        int delay = JfcloudColdChainConstants.RETRY_DELAY_MS;
        while (retries > 0) {
            try {
                log.info("正在进行重试，剩余次数: {}", retries);
                jfcloudInfluxDBService.writePojo(dataList);
                log.info("数据成功写入 InfluxDB，重试成功");
                return;
            } catch (Exception e) {
                retries--;
                log.error("重试失败，剩余重试次数: {}, 错误信息: {}", retries, e.getMessage());
                if (retries == 0) {
                    log.error("重试已达最大次数，放弃写入操作");
                }
                try {
                    Thread.sleep(delay);  // 等待一段时间后重试
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    // 定期检查并批量写入数据，作为备用机制
    @Scheduled(fixedRate = JfcloudColdChainConstants.CHECK_INTERVAL_MS)
    public void checkAndWriteData() {
        // 如果写入队列有数据，进行定期检查并触发异步写入
        if (!writeQueue.isEmpty()) {
            log.info("定期检查发现有待写入数据，执行批量写入操作");
            writeDataToDatabaseAsync();
        }
    }
}