package cn.ibizlab.core.util.config;

import cn.ibizlab.core.extensions.domain.LocalMsgEvent;
import cn.ibizlab.core.extensions.util.LocalMsgProducerService;
import cn.ibizlab.core.extensions.util.LocalMsgEventHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SleepingWaitStrategy;
import com.lmax.disruptor.WaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import com.lmax.disruptor.util.DaemonThreadFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ThreadFactory;


@Configuration
@ConditionalOnExpression("(!${rocketmq.producer.enabled:false})&&(!${rocketmq.consumer.enabled:false})")
public class LocalMsgConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public WaitStrategy waitStrategy() {
        return new SleepingWaitStrategy(200,1000*1000*10);
    }

    @Bean
    @ConditionalOnMissingBean
    public ThreadFactory threadFactory() {
        return DaemonThreadFactory.INSTANCE;
    }

    @Bean
    @ConditionalOnMissingBean
    public LocalMsgEventHandler localMsgEventHandler() {
        return new LocalMsgEventHandler();
    }


    @Bean
    @ConditionalOnClass({Disruptor.class})
    public Disruptor<LocalMsgEvent> disruptor(WaitStrategy waitStrategy, ThreadFactory threadFactory,
                                              LocalMsgEventHandler localMsgEventHandler) {
        Disruptor<LocalMsgEvent> disruptor = new Disruptor<>(() -> new LocalMsgEvent(), 1024 * 1024,
                threadFactory, ProducerType.SINGLE, waitStrategy);
        disruptor.handleEventsWith(localMsgEventHandler);

        // 启动
        disruptor.start();

        // WEB 容器关闭执行
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                // OK
                disruptor.shutdown();

                // wait up to 10 seconds for the ringbuffer to drain
                RingBuffer<LocalMsgEvent> ringBuffer = disruptor.getRingBuffer();
                for (int i = 0; i < 20; i++) {
                    if (ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize())) {
                        break;
                    }
                    try {
                        // give ringbuffer some time to drain...
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // ignored
                    }
                }
                disruptor.shutdown();
            } catch (Exception e) {
                // to do nothing
            }
        }));
        return disruptor;
    }

}
