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

import com.lingniu.ingest.core.dispatcher.Dispatcher;
import com.lingniu.ingest.identity.VehicleIdentityRegistry;
import com.lingniu.ingest.identity.VehicleIdentityResolver;
import com.lingniu.ingest.protocol.jt808.codec.BodyParser;
import com.lingniu.ingest.protocol.jt808.codec.BodyParserRegistry;
import com.lingniu.ingest.protocol.jt808.codec.Jt808MessageDecoder;
import com.lingniu.ingest.protocol.jt808.codec.parser.AuthBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.HeartbeatBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.LocationBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.LocationBatchBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.MediaEventBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.MediaUploadBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.PassthroughBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.RegisterBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.TerminalAttrsBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.TerminalParamsReportBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.UnregisterBodyParser;
import com.lingniu.ingest.protocol.jt808.downlink.Jt808CommandDispatcher;
import com.lingniu.ingest.protocol.jt808.handler.Jt808LocationHandler;
import com.lingniu.ingest.protocol.jt808.inbound.Jt808NettyServer;
import com.lingniu.ingest.protocol.jt808.mapper.Jt808EventMapper;
import com.lingniu.ingest.protocol.jt808.session.Jt808ChannelRegistry;
import com.lingniu.ingest.protocol.jt808.session.Jt808PendingRequests;
import com.lingniu.ingest.session.CommandDispatcher;
import com.lingniu.ingest.session.SessionStore;
import com.lingniu.ingest.session.config.SessionCoreAutoConfiguration;
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;

@AutoConfiguration(before = SessionCoreAutoConfiguration.class)
@EnableConfigurationProperties(Jt808Properties.class)
@ConditionalOnProperty(prefix = "lingniu.ingest.jt808", name = "enabled", havingValue = "true")
public class Jt808AutoConfiguration {

    @Bean public BodyParser jt808RegisterBodyParser() { return new RegisterBodyParser(); }
    @Bean public BodyParser jt808AuthBodyParser() { return new AuthBodyParser(); }
    @Bean public BodyParser jt808LocationBodyParser() { return new LocationBodyParser(); }
    @Bean public BodyParser jt808HeartbeatBodyParser() { return new HeartbeatBodyParser(); }
    @Bean public BodyParser jt808UnregisterBodyParser() { return new UnregisterBodyParser(); }
    @Bean public BodyParser jt808TerminalParamsReportBodyParser() { return new TerminalParamsReportBodyParser(); }
    @Bean public BodyParser jt808TerminalAttrsBodyParser() { return new TerminalAttrsBodyParser(); }
    @Bean public BodyParser jt808LocationBatchBodyParser() { return new LocationBatchBodyParser(); }
    @Bean public BodyParser jt808MediaEventBodyParser() { return new MediaEventBodyParser(); }
    @Bean public BodyParser jt808MediaUploadBodyParser() { return new MediaUploadBodyParser(); }
    @Bean public BodyParser jt808PassthroughBodyParser() { return new PassthroughBodyParser(); }

    @Bean
    @ConditionalOnMissingBean
    public BodyParserRegistry jt808BodyParserRegistry(List<BodyParser> parsers) {
        return new BodyParserRegistry(parsers);
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt808MessageDecoder jt808MessageDecoder(BodyParserRegistry registry) {
        return new Jt808MessageDecoder(registry);
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt808EventMapper jt808EventMapper(VehicleIdentityResolver identityResolver) {
        return new Jt808EventMapper(identityResolver);
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt808LocationHandler jt808LocationHandler(Jt808EventMapper mapper) {
        return new Jt808LocationHandler(mapper);
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt808ChannelRegistry jt808ChannelRegistry() {
        return new Jt808ChannelRegistry();
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt808PendingRequests jt808PendingRequests() {
        return new Jt808PendingRequests();
    }

    /**
     * JT808 模块启用时抢占 {@link CommandDispatcher} Bean。
     * 通过 {@code @AutoConfiguration(before = SessionCoreAutoConfiguration.class)} 确保本 Bean
     * 先注册，session-core 的 {@code @ConditionalOnMissingBean} 会因此跳过 Noop 默认实现。
     */
    @Bean
    @ConditionalOnMissingBean
    public CommandDispatcher jt808CommandDispatcher(SessionStore sessions,
                                                    Jt808ChannelRegistry channelRegistry,
                                                    Jt808PendingRequests pendingRequests) {
        return new Jt808CommandDispatcher(sessions, channelRegistry, pendingRequests);
    }

    @Bean
    @ConditionalOnMissingBean
    public Jt808NettyServer jt808NettyServer(Jt808Properties props,
                                             Jt808MessageDecoder decoder,
                                             Dispatcher dispatcher,
                                             SessionStore sessions,
                                             VehicleIdentityRegistry identityRegistry,
                                             VehicleIdentityResolver identityResolver,
                                             Jt808ChannelRegistry channelRegistry,
                                             Jt808PendingRequests pendingRequests) {
        return new Jt808NettyServer(props.getPort(), props.getWorkerThreads(),
                decoder, dispatcher, sessions, identityRegistry, identityResolver,
                channelRegistry, pendingRequests);
    }
}
