package com.yiqi.task;

import cn.hutool.core.collection.CollUtil;
import com.yiqi.common.core.redis.RedisUtils;
import com.yiqi.delay.DelayMessage;
import com.yiqi.delay.DelayQueueCache;
import com.yiqi.delay.impl.DelayTaskRunService;
import com.yiqi.lock.RedisLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.ExecutorService;

/**
 * @author douya
 * @description 延迟队列消息监听执行器
 * @date 2022/5/19
 */
@Component
@Slf4j
public class OrderPayDelayQueueTask {

    protected final Logger logger = LoggerFactory.getLogger(OrderPayDelayQueueTask.class);

    @Resource
    private DelayQueueCache delayQueueCache;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private RedisLockUtil redisLockUtil;

    @Resource(name = "delayTaskExecutor")
    private ExecutorService executor;
    @Resource
    private DelayTaskRunService delayTaskRunService;

    private static final String DELAY_QUEUE_LOCK = "delay_queue_lock:";

    /**
     * 延时队列机器开始运作，发送消息给到消息队列
     */
    @Scheduled(fixedDelay = 1000)
    private void startDelayQueue() {
        // 1. 幂等性控制
        String lockKey = DELAY_QUEUE_LOCK + "scan";
        if (!redisLockUtil.tryLock(lockKey)) {
            return;
        }
        try {
            // 2. 扫描到期任务
            long now = System.currentTimeMillis() / 1000;
            Set<Object> tasks = redisUtils.zRangeByScore("DELAY_TASK_CACHE", 0, now);
            if (CollUtil.isEmpty(tasks)) {
                return;
            }
            // 3. 处理任务
            for (Object task : tasks) {
                //移除缓存，如果移除成功则表示当前线程处理了延时任务，则执行延时任务
                DelayMessage delayMessage = delayQueueCache.getDelayMessageByKey(task.toString());
                if (delayMessage == null) {
                    redisUtils.zRemove("DELAY_TASK_CACHE", task.toString());
                    continue;
                }
                //暂不执行请求，如果超过60S还未启动，可能存在系统故障，则重新开启
                if (delayMessage.getIsRun() == 0) {
                    Long between = now - delayMessage.getRunTime();
                    if (between < 60) {
                        continue;
                    }
                }
                executor.submit(new Runnable() {
                    @Override
                    public void run() {
                        delayTaskRunService.handleDelayMessage(delayMessage.getTags(), delayMessage);
                    }
                });
            }

        } catch (Exception e) {
            log.error("扫描延迟队列异常", e);
        } finally {
            redisLockUtil.unlock(lockKey);
        }
    }
}
