package com.lingniu.ingest.eventhistory.config;

import com.lingniu.ingest.api.consumer.EnvelopeConsumerProcessor;
import com.lingniu.ingest.api.consumer.EnvelopeDeadLetterSink;
import com.lingniu.ingest.eventhistory.ApiExceptionHandler;
import com.lingniu.ingest.eventhistory.EventHistoryEnvelopeIngestor;
import com.lingniu.ingest.eventhistory.Gb32960DecodedFrameService;
import com.lingniu.ingest.eventhistory.Gb32960FrameController;
import com.lingniu.ingest.eventhistory.Jt808LocationHistoryController;
import com.lingniu.ingest.eventhistory.Jt808RawFrameHistoryController;
import com.lingniu.ingest.eventhistory.LocationHistoryController;
import com.lingniu.ingest.eventhistory.RawFrameHistoryController;
import com.lingniu.ingest.protocol.gb32960.codec.Gb32960MessageDecoder;
import com.lingniu.ingest.protocol.gb32960.config.Gb32960AutoConfiguration;
import com.lingniu.ingest.sink.kafka.KafkaSinkAutoConfiguration;
import com.lingniu.ingest.tdenginehistory.config.TdengineHistoryAutoConfiguration;
import com.lingniu.ingest.tdenginehistory.TdengineHistoryReader;
import com.lingniu.ingest.tdenginehistory.TdengineHistoryWriter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;

import java.net.URI;
import java.nio.file.Path;

/**
 * Event History 查询/消费服务自动装配。
 *
 * <p>该模块有两类入口：
 * <ul>
 *   <li>TDengine HTTP 查询入口：查询位置、RAW 帧和按需解码的 GB32960 帧。
 *   <li>Kafka consumer 入口：消费 envelope 并写入 TDengine 历史表。
 * </ul>
 *
 * <p>当前生产 history app 以 TDengine 为准；Kafka consumer 是否启动还取决于
 * {@code lingniu.ingest.sink.kafka.consumer.enabled=true}。
 */
@AutoConfiguration
@AutoConfigureAfter({
        Gb32960AutoConfiguration.class,
        KafkaSinkAutoConfiguration.class,
        TdengineHistoryAutoConfiguration.class
})
@ConditionalOnProperty(prefix = "lingniu.ingest.event-history", name = "enabled", havingValue = "true")
public class EventHistoryAutoConfiguration {

    @Bean
    @ConditionalOnProperty(prefix = "lingniu.ingest.tdengine-history", name = "telemetry-fields-enabled")
    public Object rejectedRemovedTelemetryFieldsSwitch() {
        throw new IllegalStateException(
                "tdengine-history.telemetry-fields-enabled has been removed; history stores raw_frames and location rows only");
    }

    @Bean
    @ConditionalOnBean(TdengineHistoryWriter.class)
    @ConditionalOnMissingBean
    public EventHistoryEnvelopeIngestor tdengineEventHistoryEnvelopeIngestor(TdengineHistoryWriter writer) {
        return new EventHistoryEnvelopeIngestor(writer);
    }

    @Bean
    @ConditionalOnBean({EventHistoryEnvelopeIngestor.class, EnvelopeDeadLetterSink.class})
    @ConditionalOnMissingBean(name = "eventHistoryEnvelopeConsumerProcessor")
    public EnvelopeConsumerProcessor eventHistoryEnvelopeConsumerProcessor(EventHistoryEnvelopeIngestor ingestor,
                                                                          EnvelopeDeadLetterSink deadLetterSink) {
        // 只注册 processor；真正拉 Kafka 的 runner 按 consumer.enabled 决定是否创建。
        return new EnvelopeConsumerProcessor("event-history", ingestor, deadLetterSink);
    }

    @Bean
    @ConditionalOnBean({EventHistoryEnvelopeIngestor.class, EnvelopeDeadLetterSink.class})
    @ConditionalOnMissingBean(name = "eventHistoryRawEnvelopeConsumerProcessor")
    public EnvelopeConsumerProcessor eventHistoryRawEnvelopeConsumerProcessor(EventHistoryEnvelopeIngestor ingestor,
                                                                             EnvelopeDeadLetterSink deadLetterSink) {
        return new EnvelopeConsumerProcessor("event-history-raw", ingestor, deadLetterSink);
    }

    @Bean
    @ConditionalOnMissingBean
    public ApiExceptionHandler apiExceptionHandler() {
        return new ApiExceptionHandler();
    }

    @Bean
    @ConditionalOnBean(Gb32960MessageDecoder.class)
    @ConditionalOnMissingBean
    public Gb32960DecodedFrameService gb32960DecodedFrameService(ObjectProvider<TdengineHistoryReader> reader,
                                                                 Gb32960MessageDecoder decoder,
                                                                 @Value("${lingniu.ingest.event-history.archive-path:${SINK_ARCHIVE_PATH:./archive/}}")
                                                                 String archivePath) {
        return new Gb32960DecodedFrameService(reader.getIfAvailable(), decoder, archiveRoot(archivePath), null);
    }

    @Bean
    @ConditionalOnBean(Gb32960DecodedFrameService.class)
    @ConditionalOnProperty(prefix = "lingniu.ingest.event-history.api", name = "specialized-enabled", havingValue = "true")
    @ConditionalOnMissingBean
    public Gb32960FrameController gb32960FrameController(Gb32960DecodedFrameService service) {
        return new Gb32960FrameController(service);
    }

    @Bean
    @ConditionalOnBean(TdengineHistoryReader.class)
    @ConditionalOnMissingBean
    public LocationHistoryController locationHistoryController(TdengineHistoryReader reader) {
        return new LocationHistoryController(reader);
    }

    @Bean
    @ConditionalOnBean(TdengineHistoryReader.class)
    @ConditionalOnMissingBean
    public RawFrameHistoryController rawFrameHistoryController(TdengineHistoryReader reader) {
        return new RawFrameHistoryController(reader);
    }

    @Bean
    @ConditionalOnBean(TdengineHistoryReader.class)
    @ConditionalOnProperty(prefix = "lingniu.ingest.event-history.api", name = "specialized-enabled", havingValue = "true")
    @ConditionalOnMissingBean
    public Jt808LocationHistoryController jt808LocationHistoryController(TdengineHistoryReader reader) {
        return new Jt808LocationHistoryController(reader);
    }

    @Bean
    @ConditionalOnBean(TdengineHistoryReader.class)
    @ConditionalOnProperty(prefix = "lingniu.ingest.event-history.api", name = "specialized-enabled", havingValue = "true")
    @ConditionalOnMissingBean
    public Jt808RawFrameHistoryController jt808RawFrameHistoryController(TdengineHistoryReader reader) {
        return new Jt808RawFrameHistoryController(reader);
    }

    static Path archiveRoot(String value) {
        if (value == null || value.isBlank()) {
            return Path.of(System.getProperty("java.io.tmpdir"), "lingniu-archive");
        }
        // 支持 file:// URI，便于部署配置里统一用 URI 风格表达 archive 根路径。
        if (value.startsWith("file://")) {
            return Path.of(URI.create(value));
        }
        return Path.of(value);
    }
}
