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

import com.lingniu.ingest.core.dispatcher.Dispatcher;
import com.lingniu.ingest.protocol.gb32960.auth.Gb32960PlatformAuthorizer;
import com.lingniu.ingest.protocol.gb32960.auth.Gb32960VinAuthorizer;
import com.lingniu.ingest.protocol.gb32960.codec.Gb32960BodyParser;
import com.lingniu.ingest.protocol.gb32960.codec.Gb32960CommandParser;
import com.lingniu.ingest.protocol.gb32960.codec.Gb32960MessageDecoder;
import com.lingniu.ingest.protocol.gb32960.codec.InfoBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.InfoBlockParserRegistry;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.AlarmV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.DriveMotorV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.EngineV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.ExtremeValueV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.FuelCellV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.PositionV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.TemperatureV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.VehicleV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2016.VoltageV2016BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.AlarmV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.BatteryTemperatureV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.DriveMotorV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.EngineV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.FuelCellStackV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.FuelCellV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.MinParallelVoltageV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.PositionV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.SuperCapacitorExtremeV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.SuperCapacitorV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.v2025.VehicleV2025BlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcAirConditionerBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcAuxiliaryBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcDcDcBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcDemoExtensionBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcStackBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcVehicleInfoBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong.GdFcVendorTlvBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.profile.Gb32960ProfileRegistry;
import com.lingniu.ingest.protocol.gb32960.codec.profile.RuleBasedVendorExtensionSelector;
import com.lingniu.ingest.protocol.gb32960.codec.profile.VendorExtensionCatalog;
import com.lingniu.ingest.protocol.gb32960.codec.profile.VendorExtensionSelector;
import com.lingniu.ingest.protocol.gb32960.handler.Gb32960RealtimeHandler;
import com.lingniu.ingest.protocol.gb32960.inbound.Gb32960AccessService;
import com.lingniu.ingest.protocol.gb32960.inbound.Gb32960AckService;
import com.lingniu.ingest.protocol.gb32960.inbound.Gb32960ConnectionDiagnostics;
import com.lingniu.ingest.protocol.gb32960.inbound.Gb32960FrameDiagnostics;
import com.lingniu.ingest.protocol.gb32960.inbound.Gb32960NettyServer;
import com.lingniu.ingest.protocol.gb32960.mapper.Gb32960EventMapper;
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;

/**
 * GB/T 32960.3 协议接入模块的自动装配。
 *
 * <p>每个 Parser Bean 都会被 {@link InfoBlockParserRegistry} 按
 * {@code (ProtocolVersion, typeCode)} 注册。2016/2025 可同时加载。
 *
 * <p>只有 {@code lingniu.ingest.gb32960.enabled=true} 时才会装配 32960 协议解析组件。
 * TCP 监听由 {@code lingniu.ingest.gb32960.server.enabled} 单独控制。
 */
@AutoConfiguration
@EnableConfigurationProperties(Gb32960Properties.class)
@ConditionalOnProperty(prefix = "lingniu.ingest.gb32960", name = "enabled", havingValue = "true")
public class Gb32960AutoConfiguration {

    // ================= 2016 版信息体 Parser（com...parser.v2016 包） =================

    @Bean public InfoBlockParser gb32960V2016Vehicle() { return new VehicleV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016DriveMotor() { return new DriveMotorV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016FuelCell() { return new FuelCellV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016Engine() { return new EngineV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016Position() { return new PositionV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016Extreme() { return new ExtremeValueV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016Alarm() { return new AlarmV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016Voltage() { return new VoltageV2016BlockParser(); }
    @Bean public InfoBlockParser gb32960V2016Temperature() { return new TemperatureV2016BlockParser(); }
    // 注意：0x30~0x7F 在 GB/T 32960.3-2016 附录 B 表 B.3 是"预留"区段，没有任何字段定义。
    // peer 在 V2016 帧里发 0x30/0x31/0x32 是越界使用，强行用 2025 字段布局解读会得到非物理值。
    // 故 V2016 不注册任何 0x30+ parser；遇到时由 Gb32960BodyParser 走 Raw 兜底并打 WARN。

    // ================= 2025 版信息体 Parser（com...parser.v2025 包） =================

    @Bean public InfoBlockParser gb32960V2025Vehicle() { return new VehicleV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025DriveMotor() { return new DriveMotorV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025FuelCell() { return new FuelCellV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025Engine() { return new EngineV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025Position() { return new PositionV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025Alarm() { return new AlarmV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025MinParallelVoltage() { return new MinParallelVoltageV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025BatteryTemp() { return new BatteryTemperatureV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025FuelCellStack() { return new FuelCellStackV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025SuperCap() { return new SuperCapacitorV2025BlockParser(); }
    @Bean public InfoBlockParser gb32960V2025SuperCapExtreme() { return new SuperCapacitorExtremeV2025BlockParser(); }

    // ================= Vendor 扩展套件目录 =================

    /**
     * 内置 vendor 扩展套件目录。当前注册：
     * <ul>
     *   <li>{@code guangdong-fc} —— 广东燃料电池汽车示范规范 0x30~0x34、0x80
     * </ul>
     * 未来新增其他厂商扩展时直接在这里加 entry。
     */
    @Bean
    @ConditionalOnMissingBean
    public VendorExtensionCatalog gb32960VendorExtensionCatalog() {
        return new VendorExtensionCatalog(java.util.Map.of(
                "guangdong-fc", List.of(
                        new GdFcStackBlockParser(),
                        new GdFcAuxiliaryBlockParser(),
                        new GdFcDcDcBlockParser(),
                        new GdFcAirConditionerBlockParser(),
                        new GdFcVehicleInfoBlockParser(),
                        new GdFcDemoExtensionBlockParser(),
                        // 0x83 厂商私有 TLV 兜底（同 peer 在广东规范之外又下发的未公开扩展）
                        // 这里只注册已经在线上见过的 typeCode；新增 typeCode 应先确认长度字段格式。
                        new GdFcVendorTlvBlockParser(0x83))));
    }

    // ================= Core components =================

    /**
     * Profile 注册表：把全部已注入的标准 parser 作为 default profile，
     * 同时按配置 {@code lingniu.ingest.gb32960.vendor-extensions} 里被引用的 vendor 套件名
     * 分别构建一份 "default + vendor" 的 registry。
     */
    @Bean
    @ConditionalOnMissingBean
    public Gb32960ProfileRegistry gb32960ProfileRegistry(List<InfoBlockParser> parsers,
                                                         VendorExtensionCatalog catalog,
                                                         Gb32960Properties props) {
        java.util.Set<String> enabled = new java.util.LinkedHashSet<>();
        for (Gb32960Properties.VendorExtension e : props.getVendorExtensions()) {
            if (e.getName() != null && !e.getName().isBlank()) enabled.add(e.getName());
        }
        // enabled 只来自配置里实际引用过的扩展，避免无关 vendor parser 进入默认解析路径。
        return new Gb32960ProfileRegistry(parsers, catalog, enabled);
    }

    /** Vendor 扩展选择器：按配置 list 顺序首匹。 */
    @Bean
    @ConditionalOnMissingBean
    public VendorExtensionSelector gb32960VendorExtensionSelector(Gb32960Properties props,
                                                                  VendorExtensionCatalog catalog) {
        if (props.getVendorExtensions() == null || props.getVendorExtensions().isEmpty()) {
            // 没有 vendor 配置时强制 NONE，0x30+ 在 2016 帧里会 Raw 兜底，防止误套扩展解析。
            return VendorExtensionSelector.NONE;
        }
        return new RuleBasedVendorExtensionSelector(props.getVendorExtensions(), catalog.names());
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960BodyParser gb32960BodyParser(Gb32960ProfileRegistry profileRegistry,
                                               VendorExtensionSelector selector,
                                               Gb32960Properties props) {
        Gb32960BodyParser parser = new Gb32960BodyParser(profileRegistry, selector);
        parser.setLenientBlockFailure(props.getParse().isLenientBlockFailure());
        return parser;
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960CommandParser gb32960CommandParser() {
        return new Gb32960CommandParser();
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960MessageDecoder gb32960MessageDecoder(Gb32960BodyParser bodyParser,
                                                        Gb32960CommandParser commandParser) {
        return new Gb32960MessageDecoder(bodyParser, commandParser);
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960EventMapper gb32960EventMapper() {
        return new Gb32960EventMapper();
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960RealtimeHandler gb32960RealtimeHandler(Gb32960EventMapper mapper) {
        return new Gb32960RealtimeHandler(mapper);
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960VinAuthorizer gb32960VinAuthorizer(Gb32960Properties props) {
        return new Gb32960VinAuthorizer(props.getAuth());
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960PlatformAuthorizer gb32960PlatformAuthorizer(Gb32960Properties props) {
        return new Gb32960PlatformAuthorizer(props.getAuth().getPlatforms());
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960AccessService gb32960AccessService(Gb32960VinAuthorizer authorizer,
                                                     Gb32960PlatformAuthorizer platformAuthorizer) {
        return new Gb32960AccessService(authorizer, platformAuthorizer);
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960AckService gb32960AckService() {
        return new Gb32960AckService();
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960FrameDiagnostics gb32960FrameDiagnostics(Gb32960Properties props) {
        return new Gb32960FrameDiagnostics(
                props.getDiagnostics().getMaxLoggedFrameKeysPerChannel());
    }

    @Bean
    @ConditionalOnMissingBean
    public Gb32960ConnectionDiagnostics gb32960ConnectionDiagnostics() {
        return new Gb32960ConnectionDiagnostics();
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "lingniu.ingest.gb32960.server", name = "enabled",
            havingValue = "true", matchIfMissing = true)
    public Gb32960NettyServer gb32960NettyServer(Gb32960Properties props,
                                                 Gb32960MessageDecoder decoder,
                                                 Dispatcher dispatcher,
                                                 Gb32960AccessService accessService,
                                                 Gb32960AckService ackService,
                                                 Gb32960FrameDiagnostics diagnostics,
                                                 Gb32960ConnectionDiagnostics connectionDiagnostics) {
        return new Gb32960NettyServer(
                props.getPort(),
                props.getWorkerThreads(),
                props.getIdleReadSeconds(),
                decoder,
                dispatcher,
                accessService,
                ackService,
                diagnostics,
                connectionDiagnostics,
                props.getTls());
    }
}
