package com.lingniu.ingest.protocol.jt1078.config;

import com.lingniu.ingest.core.concurrency.DisruptorEventBus;
import com.lingniu.ingest.core.dispatcher.Dispatcher;
import com.lingniu.ingest.identity.VehicleIdentityResolver;
import com.lingniu.ingest.protocol.jt1078.codec.parser.FileUploadCompleteBodyParser;
import com.lingniu.ingest.protocol.jt1078.codec.parser.FileListBodyParser;
import com.lingniu.ingest.protocol.jt1078.codec.parser.MediaAttributesBodyParser;
import com.lingniu.ingest.protocol.jt1078.codec.parser.PassengerVolumeBodyParser;
import com.lingniu.ingest.protocol.jt1078.handler.Jt1078MalformedRtpHandler;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078MalformedRtpEventPublisher;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078MediaArchiveService;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078MediaStreamServer;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078UdpMediaStreamServer;
import com.lingniu.ingest.protocol.jt808.codec.BodyParser;
import com.lingniu.ingest.protocol.jt808.config.Jt808AutoConfiguration;
import com.lingniu.ingest.sink.archive.ArchiveStore;
import com.lingniu.ingest.sink.archive.config.SinkArchiveAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
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;

/**
 * jt1078 在 jt808 之前装配它自己的 Parser Bean，Spring 会把它们注入到 jt808 的
 * {@code BodyParserRegistry} 里，实现"同一个 Netty 端口复用、消息集热插拔"。
 */
@AutoConfiguration(before = Jt808AutoConfiguration.class, after = SinkArchiveAutoConfiguration.class)
@EnableConfigurationProperties(Jt1078Properties.class)
@ConditionalOnProperty(prefix = "lingniu.ingest.jt1078", name = "enabled", havingValue = "true")
public class Jt1078AutoConfiguration {

    @Bean
    public BodyParser jt1078MediaAttributesBodyParser() {
        return new MediaAttributesBodyParser();
    }

    @Bean
    public BodyParser jt1078PassengerVolumeBodyParser() {
        return new PassengerVolumeBodyParser();
    }

    @Bean
    public BodyParser jt1078FileListBodyParser() {
        return new FileListBodyParser();
    }

    @Bean
    public BodyParser jt1078FileUploadCompleteBodyParser() {
        return new FileUploadCompleteBodyParser();
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(ArchiveStore.class)
    public Jt1078MediaArchiveService jt1078MediaArchiveService(ArchiveStore archive,
                                                               VehicleIdentityResolver identityResolver,
                                                               DisruptorEventBus eventBus,
                                                               Jt1078Properties props) {
        return new Jt1078MediaArchiveService(
                archive, identityResolver, eventBus::publish, props.getMediaStream().getSegmentSeconds());
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt1078MalformedRtpEventPublisher jt1078MalformedRtpEventPublisher(VehicleIdentityResolver identityResolver,
                                                                             Dispatcher dispatcher) {
        return new Jt1078MalformedRtpEventPublisher(identityResolver, dispatcher::dispatch);
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt1078MalformedRtpHandler jt1078MalformedRtpHandler(VehicleIdentityResolver identityResolver) {
        return new Jt1078MalformedRtpHandler(identityResolver);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(Jt1078MediaArchiveService.class)
    @ConditionalOnExpression("${lingniu.ingest.jt1078.media-stream.enabled:true} "
            + "&& ${lingniu.ingest.jt1078.media-stream.tcp-enabled:true}")
    public Jt1078MediaStreamServer jt1078MediaStreamServer(Jt1078Properties props,
                                                           Jt1078MediaArchiveService archiveService,
                                                           Jt1078MalformedRtpEventPublisher malformedPublisher) {
        Jt1078Properties.MediaStream media = props.getMediaStream();
        return new Jt1078MediaStreamServer(
                media.getPort(), media.getWorkerThreads(), media.getMaxPacketLength(), archiveService, malformedPublisher);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(Jt1078MediaArchiveService.class)
    @ConditionalOnExpression("${lingniu.ingest.jt1078.media-stream.enabled:true} "
            + "&& ${lingniu.ingest.jt1078.media-stream.udp-enabled:false}")
    public Jt1078UdpMediaStreamServer jt1078UdpMediaStreamServer(Jt1078Properties props,
                                                                 Jt1078MediaArchiveService archiveService,
                                                                 Jt1078MalformedRtpEventPublisher malformedPublisher) {
        Jt1078Properties.MediaStream media = props.getMediaStream();
        return new Jt1078UdpMediaStreamServer(
                media.getUdpPort(), media.getWorkerThreads(), media.getMaxPacketLength(), archiveService, malformedPublisher);
    }
}
