package com.lingniu.ingest.sink.kafka;

import com.lingniu.ingest.api.consumer.EnvelopeConsumerProcessor;
import com.lingniu.ingest.api.consumer.EnvelopeIngestResult;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;

class KafkaEnvelopeConsumerFactoryTest {

    @Test
    void createsDefaultIndependentConsumersForKnownServiceProcessors() {
        List<Properties> created = new ArrayList<>();
        KafkaEnvelopeConsumerFactory factory = new KafkaEnvelopeConsumerFactory(props -> {
            created.add(props);
            return new MockConsumer<>(OffsetResetStrategy.EARLIEST);
        });
        KafkaSinkProperties props = new KafkaSinkProperties();
        props.setBootstrapServers("kafka-1:9092");
        EnvelopeConsumerProcessor stateProcessor = processor();
        EnvelopeConsumerProcessor statProcessor = processor();

        List<KafkaEnvelopeConsumerWorker> workers = factory.createWorkers(Map.of(
                "vehicleStateEnvelopeConsumerProcessor", stateProcessor,
                "vehicleStatEnvelopeConsumerProcessor", statProcessor), props);

        assertThat(workers).hasSize(2);
        assertThat(created)
                .extracting(p -> p.getProperty(ConsumerConfig.GROUP_ID_CONFIG))
                .containsExactly("vehicle-state", "vehicle-stat");
        assertThat(created)
                .allSatisfy(p -> {
                    assertThat(p.getProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)).isEqualTo("kafka-1:9092");
                    assertThat(p.get(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG)).isEqualTo(false);
                    assertThat(p.get(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG)).isEqualTo(1800000);
                });
    }

    @Test
    void createsParallelConsumersForEachBindingWhenConsumerConcurrencyIsConfigured() {
        List<Properties> created = new ArrayList<>();
        KafkaEnvelopeConsumerFactory factory = new KafkaEnvelopeConsumerFactory(props -> {
            created.add(props);
            return new MockConsumer<>(OffsetResetStrategy.EARLIEST);
        });
        KafkaSinkProperties props = new KafkaSinkProperties();
        props.getConsumer().setConcurrency(3);
        EnvelopeConsumerProcessor stateProcessor = processor();

        List<KafkaEnvelopeConsumerWorker> workers = factory.createWorkers(Map.of(
                "vehicleStateEnvelopeConsumerProcessor", stateProcessor), props);

        assertThat(workers).hasSize(3);
        assertThat(created)
                .extracting(p -> p.getProperty(ConsumerConfig.GROUP_ID_CONFIG))
                .containsExactly("vehicle-state", "vehicle-state", "vehicle-state");
        assertThat(created)
                .extracting(p -> p.getProperty(ConsumerConfig.CLIENT_ID_CONFIG))
                .containsExactly(
                        "lingniu-envelope-consumer-vehicleStateEnvelopeConsumerProcessor-0",
                        "lingniu-envelope-consumer-vehicleStateEnvelopeConsumerProcessor-1",
                        "lingniu-envelope-consumer-vehicleStateEnvelopeConsumerProcessor-2");
    }

    private EnvelopeConsumerProcessor processor() {
        return new EnvelopeConsumerProcessor(
                "service",
                bytes -> EnvelopeIngestResult.processed("evt-1", "VIN001"),
                record -> {});
    }
}
