package cn.reghao.tnb.content.app.vod.service.rcmd.task;

import cn.reghao.tnb.content.app.util.redis.ds.RedisList;
import cn.reghao.tnb.content.app.util.redis.ds.RedisSet;
import cn.reghao.tnb.content.app.vod.service.ContentPermission;
import cn.reghao.tnb.content.app.vod.service.VideoPostQuery;
import cn.reghao.tnb.content.app.vod.service.rcmd.UserInterestBased;
import cn.reghao.tnb.user.api.iface.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import java.util.concurrent.Executor;

/**
 * @author reghao
 * @date 2024-12-22 21:19:57
 */
@Slf4j
@Component
public class RcmdConsumer {
    @DubboReference(check = false)
    private UserService userService;

    private final Executor taskExecutor;
    private final Object monitor;
    private final RcmdProducer rcmdProducer;
    private final VideoPostQuery videoPostQuery;
    private final RedisSet redisSet;
    private final RedisList redisList;
    private final ContentPermission contentPermission;
    private final UserInterestBased userInterestBased;

    public RcmdConsumer(@Qualifier("taskExecutor") Executor taskExecutor, VideoPostQuery videoPostQuery, RedisSet redisSet, RedisList redisList,
                        ContentPermission contentPermission, RcmdProducer rcmdProducer, UserInterestBased userInterestBased) {
        this.taskExecutor = taskExecutor;
        this.videoPostQuery = videoPostQuery;
        this.redisSet = redisSet;
        this.redisList = redisList;
        this.contentPermission = contentPermission;
        this.monitor = rcmdProducer.getMonitor();
        this.rcmdProducer = rcmdProducer;
        this.userInterestBased = userInterestBased;
    }

    @PostConstruct
    public void run() {
        taskExecutor.execute(new ConsumerThread());
        log.info("rcmd producer-consumer 模型启动...");
    }

    class ConsumerThread implements Runnable {
        @Override
        public void run() {
            ThreadPoolTaskExecutor executor = (ThreadPoolTaskExecutor) taskExecutor;
            int capacity = executor.getQueueCapacity();
            while (!Thread.interrupted()) {
                try {
                    if (executor.getQueueSize() < capacity) {
                        dispatch();
                    } else {
                        //log.info("当前有 {} 个活跃线程, 休眠 10s 等待线程池空闲...", tpe.getActiveCount());
                        Thread.sleep(10_000);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void dispatch() throws Exception {
        synchronized (monitor) {
            Object object = rcmdProducer.get();
            if (object != null) {
                if (object instanceof RcmdData) {
                    RcmdData rcmdData = (RcmdData) object;
                    String requestId = rcmdData.getRequestId();
                    MDC.put("request_id", requestId);

                    int mode = userService.getRecommendMode(rcmdData.getUserId());
                    RcmdTask rcmdTask = new RcmdTask(rcmdData, videoPostQuery, redisSet, redisList, contentPermission, mode);
                    taskExecutor.execute(rcmdTask);
                } else {
                    log.error("Object 类型未知");
                }
            } else {
                log.info("调用 monitor.wait() 等待 DataProducer 中有数据可用");
                monitor.wait();
            }
        }
    }
}
