package com.lingniu.ingest.core.config;

import com.lingniu.ingest.api.pipeline.IngestInterceptor;
import com.lingniu.ingest.api.sink.EventSink;
import com.lingniu.ingest.core.concurrency.AsyncBatchExecutor;
import com.lingniu.ingest.core.concurrency.DisruptorEventBus;
import com.lingniu.ingest.core.dispatcher.AnnotationHandlerBeanPostProcessor;
import com.lingniu.ingest.core.dispatcher.Dispatcher;
import com.lingniu.ingest.core.dispatcher.HandlerInvoker;
import com.lingniu.ingest.core.dispatcher.HandlerRegistry;
import com.lingniu.ingest.core.pipeline.InterceptorChain;
import com.lingniu.ingest.core.pipeline.builtin.DedupInterceptor;
import com.lingniu.ingest.core.pipeline.builtin.RateLimitInterceptor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.List;

/**
 * ingest-core 的自动装配入口。所有 Bean 都是 {@code @ConditionalOnMissingBean}，便于下游替换。
 *
 * <p>生产链路顺序：入口收到 {@code RawFrame} → {@link InterceptorChain} 做准入 →
 * {@link Dispatcher} 定位协议 Handler → Handler 产出 {@code VehicleEvent} →
 * {@link DisruptorEventBus} 扇出到 Archive、Kafka、历史索引等 {@code EventSink}。
 */
@AutoConfiguration
@EnableConfigurationProperties(IngestCoreProperties.class)
public class IngestCoreAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public HandlerRegistry handlerRegistry() {
        return new HandlerRegistry();
    }

    @Bean
    @ConditionalOnMissingBean
    public HandlerInvoker handlerInvoker() {
        return new HandlerInvoker();
    }

    @Bean
    public static AnnotationHandlerBeanPostProcessor annotationHandlerBeanPostProcessor() {
        return new AnnotationHandlerBeanPostProcessor();
    }

    @Bean
    @ConditionalOnProperty(prefix = "lingniu.ingest.pipeline.dedup", name = "enabled", havingValue = "true", matchIfMissing = true)
    public DedupInterceptor dedupInterceptor(IngestCoreProperties props) {
        // 去重尽量放在限流前，重复包不应消耗后续每 VIN QPS 配额。
        return new DedupInterceptor(props.getDedup().getCacheSize(), props.getDedup().getTtlSeconds());
    }

    @Bean
    public RateLimitInterceptor rateLimitInterceptor(IngestCoreProperties props) {
        return new RateLimitInterceptor(props.getRateLimit().getPerVinQps(), props.getRateLimit().getMaxVins());
    }

    @Bean
    @ConditionalOnMissingBean
    public InterceptorChain interceptorChain(List<IngestInterceptor> interceptors) {
        return new InterceptorChain(interceptors);
    }

    @Bean(destroyMethod = "close")
    @ConditionalOnMissingBean
    public DisruptorEventBus disruptorEventBus(IngestCoreProperties props, List<EventSink> sinks) {
        return new DisruptorEventBus(
                props.getDisruptor().getRingBufferSize(),
                props.getDisruptor().getWaitStrategy(),
                sinks);
    }

    @Bean(destroyMethod = "close")
    @ConditionalOnMissingBean
    public AsyncBatchExecutor asyncBatchExecutor(DisruptorEventBus eventBus) {
        return new AsyncBatchExecutor(eventBus::publish);
    }

    @Bean
    @ConditionalOnMissingBean
    public Dispatcher dispatcher(HandlerRegistry registry,
                                 InterceptorChain chain,
                                 HandlerInvoker invoker,
                                 DisruptorEventBus eventBus,
                                 AsyncBatchExecutor batchExecutor) {
        return new Dispatcher(registry, chain, invoker, eventBus, batchExecutor);
    }
}
