package com.lingniu.ingest.observability;

import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.event.VehicleEvent;
import com.lingniu.ingest.api.pipeline.IngestContext;
import com.lingniu.ingest.api.pipeline.RawFrame;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;

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

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

class IngestMetricsTest {

    @Test
    void countsErrorsAgainstTheFrameProtocolCapturedInBefore() {
        SimpleMeterRegistry registry = new SimpleMeterRegistry();
        IngestMetrics metrics = new IngestMetrics(registry);
        IngestContext context = new IngestContext("trace-1");

        metrics.before(frame(ProtocolId.JT808), context);
        metrics.onError(new IllegalStateException("boom"), context);

        assertThat(registry.counter("ingest_errors_total", "protocol", "JT808").count())
                .isEqualTo(1.0);
        assertThat(registry.find("ingest_errors_total").tag("protocol", "unknown").counter())
                .isNull();
    }

    @Test
    void recordsFrameDurationWhenProcessingFailsAfterBefore() {
        SimpleMeterRegistry registry = new SimpleMeterRegistry();
        IngestMetrics metrics = new IngestMetrics(registry);
        IngestContext context = new IngestContext("trace-2");

        metrics.before(frame(ProtocolId.MQTT_YUTONG), context);
        metrics.onError(new RuntimeException("boom"), context);

        assertThat(registry.timer("ingest_frame_duration_seconds", "protocol", "MQTT_YUTONG").count())
                .isEqualTo(1);
    }

    @Test
    void recordsFrameDurationAgainstTheFrameProtocolCapturedInBefore() {
        SimpleMeterRegistry registry = new SimpleMeterRegistry();
        IngestMetrics metrics = new IngestMetrics(registry);
        IngestContext context = new IngestContext("trace-4");

        metrics.before(frame(ProtocolId.JT808), context);
        metrics.after(new VehicleEvent.Heartbeat(
                "event-1",
                "VIN001",
                ProtocolId.UNKNOWN,
                Instant.parse("2026-07-01T00:00:01Z"),
                Instant.parse("2026-07-01T00:00:02Z"),
                "trace-4",
                Map.of()), context);

        assertThat(registry.timer("ingest_frame_duration_seconds", "protocol", "JT808").count())
                .isEqualTo(1);
        assertThat(registry.find("ingest_frame_duration_seconds").tag("protocol", "unknown").timer())
                .isNull();
    }

    @Test
    void countsErrorsAsUnknownWhenThereIsNoFrameProtocolContext() {
        SimpleMeterRegistry registry = new SimpleMeterRegistry();
        IngestMetrics metrics = new IngestMetrics(registry);

        metrics.onError(new IllegalStateException("boom"), new IngestContext("trace-3"));

        assertThat(registry.counter("ingest_errors_total", "protocol", "unknown").count())
                .isEqualTo(1.0);
    }

    private static RawFrame frame(ProtocolId protocolId) {
        return new RawFrame(
                protocolId,
                0x0200,
                0,
                null,
                new byte[]{0x01},
                Map.of(),
                Instant.parse("2026-07-01T00:00:00Z"));
    }
}
