package com.lingniu.ingest.sink.kafka;

import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.event.LocationPayload;
import com.lingniu.ingest.api.event.VehicleEvent;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.time.Instant;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class KafkaEventSinkTest {

    @Test
    void acceptsRawArchiveRecordsForSplitServiceKafkaBoundary() {
        KafkaEventSink sink = new KafkaEventSink(
                null,
                new EnvelopeMapper("node-1"),
                new TopicRouter(new KafkaSinkProperties.Topics()),
                "vehicle.dlq.gb32960.v1",
                CircuitBreaker.ofDefaults("kafka-test"));

        assertThat(sink.accepts(rawArchive())).isTrue();
    }

    @Test
    void usesPhoneAsKafkaKeyWhenVinIsUnknown() {
        @SuppressWarnings("unchecked")
        KafkaProducer<String, byte[]> producer = mock(KafkaProducer.class);
        @SuppressWarnings("unchecked")
        ArgumentCaptor<ProducerRecord<String, byte[]>> sent = ArgumentCaptor.forClass(ProducerRecord.class);
        when(producer.send(sent.capture(), any())).thenAnswer(invocation -> {
            invocation.<Callback>getArgument(1).onCompletion(null, null);
            return CompletableFuture.completedFuture(null);
        });
        KafkaEventSink sink = new KafkaEventSink(
                producer,
                new EnvelopeMapper("node-1"),
                new TopicRouter(new KafkaSinkProperties.Topics()),
                "vehicle.dlq.gb32960.v1",
                CircuitBreaker.ofDefaults("kafka-test"));

        sink.publish(jt808Location()).join();

        assertThat(sent.getValue().key()).isEqualTo("phone:13079979000");
    }

    private static VehicleEvent.RawArchive rawArchive() {
        return new VehicleEvent.RawArchive(
                "raw-1",
                "VIN001",
                ProtocolId.GB32960,
                Instant.parse("2026-06-23T07:00:00Z"),
                Instant.parse("2026-06-23T07:00:01Z"),
                "trace-raw-1",
                Map.of("platformAccount", "Hyundai"),
                0x02,
                0,
                new byte[] {0x23, 0x23});
    }

    private static VehicleEvent.Location jt808Location() {
        return new VehicleEvent.Location(
                "loc-1",
                "unknown",
                ProtocolId.JT808,
                Instant.parse("2026-06-29T11:22:00Z"),
                Instant.parse("2026-06-29T11:22:01Z"),
                "trace-loc-1",
                Map.of("phone", "13079979000"),
                new LocationPayload(121.1, 31.2, 8.0, 40.0, 90.0, 0L, 1L, null));
    }
}
