package com.lingniu.ingest.protocol.jsatl12.handler;

import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.event.VehicleEvent;
import com.lingniu.ingest.protocol.jsatl12.inbound.Jsatl12ArchiveFailure;
import com.lingniu.ingest.protocol.jsatl12.inbound.Jsatl12ArchivedChunk;
import com.lingniu.ingest.protocol.jsatl12.inbound.Jsatl12MalformedFrame;
import com.lingniu.ingest.protocol.jsatl12.inbound.Jsatl12MalformedJtMessage;
import org.junit.jupiter.api.Test;

import java.time.Instant;
import java.util.List;

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

class Jsatl12ArchiveEventHandlerTest {

    @Test
    void archivedDataChunkProducesMediaMetaEvent() {
        Jsatl12ArchiveEventHandler handler = new Jsatl12ArchiveEventHandler();
        Jsatl12ArchivedChunk chunk = new Jsatl12ArchivedChunk(
                "file:///archive/jsatl12/2026/06/22/peer/file.bin",
                "jsatl12/2026/06/22/peer/file.bin",
                "ADAS_001.jpg",
                64,
                128,
                128,
                "10.0.0.8:7612",
                Instant.parse("2026-06-22T01:02:03Z"));

        List<VehicleEvent> events = handler.onDataChunkArchived(chunk);

        assertThat(events).singleElement().satisfies(event -> {
            assertThat(event).isInstanceOf(VehicleEvent.MediaMeta.class);
            VehicleEvent.MediaMeta media = (VehicleEvent.MediaMeta) event;
            assertThat(media.source()).isEqualTo(ProtocolId.JSATL12);
            assertThat(media.vin()).isEqualTo("unknown");
            assertThat(media.eventTime()).isEqualTo(Instant.parse("2026-06-22T01:02:03Z"));
            assertThat(media.archiveRef()).isEqualTo("file:///archive/jsatl12/2026/06/22/peer/file.bin");
            assertThat(media.sizeBytes()).isEqualTo(128);
            assertThat(media.mediaType()).isEqualTo("jsatl12-data-chunk");
            assertThat(media.metadata())
                    .containsEntry("vin", "unknown")
                    .containsEntry("archiveKey", "jsatl12/2026/06/22/peer/file.bin")
                    .containsEntry("fileName", "ADAS_001.jpg")
                    .containsEntry("fileOffset", "64")
                    .containsEntry("declaredChunkSizeBytes", "128")
                    .containsEntry("identityResolved", "false")
                    .containsEntry("identitySource", "UNKNOWN");
        });
    }

    @Test
    void archivedDataChunkKeepsResolvedVehicleIdentity() {
        Jsatl12ArchiveEventHandler handler = new Jsatl12ArchiveEventHandler();
        Jsatl12ArchivedChunk chunk = new Jsatl12ArchivedChunk(
                "file:///archive/jsatl12/2026/06/22/peer/file.bin",
                "jsatl12/2026/06/22/peer/file.bin",
                "ADAS_001.jpg",
                0,
                128,
                128,
                "10.0.0.8:7612",
                Instant.parse("2026-06-22T01:02:03Z"),
                "123456789012",
                "LNVIN00000001212",
                true,
                "BOUND_PHONE");

        List<VehicleEvent> events = handler.onDataChunkArchived(chunk);

        assertThat(events).singleElement().satisfies(event -> {
            assertThat(event).isInstanceOf(VehicleEvent.MediaMeta.class);
            VehicleEvent.MediaMeta media = (VehicleEvent.MediaMeta) event;
            assertThat(media.vin()).isEqualTo("LNVIN00000001212");
            assertThat(media.metadata())
                    .containsEntry("vin", "LNVIN00000001212")
                    .containsEntry("phone", "123456789012")
                    .containsEntry("identityResolved", "true")
                    .containsEntry("identitySource", "BOUND_PHONE");
        });
    }

    @Test
    void malformedJtMessageProducesPassthroughEvent() {
        Jsatl12ArchiveEventHandler handler = new Jsatl12ArchiveEventHandler();
        byte[] raw = new byte[]{0x01, 0x02, 0x03};
        Jsatl12MalformedJtMessage malformed = new Jsatl12MalformedJtMessage(
                raw,
                "10.0.0.8:7612",
                "jt808 frame too short",
                Instant.parse("2026-06-22T01:02:03Z"));

        List<VehicleEvent> events = handler.onMalformedJtMessage(malformed);

        assertThat(events).singleElement().satisfies(event -> {
            assertThat(event).isInstanceOf(VehicleEvent.Passthrough.class);
            VehicleEvent.Passthrough passthrough = (VehicleEvent.Passthrough) event;
            assertThat(passthrough.source()).isEqualTo(ProtocolId.JSATL12);
            assertThat(passthrough.vin()).isEqualTo("unknown");
            assertThat(passthrough.eventTime()).isEqualTo(Instant.parse("2026-06-22T01:02:03Z"));
            assertThat(passthrough.metadata())
                    .containsEntry("vin", "unknown")
                    .containsEntry("peer", "10.0.0.8:7612")
                    .containsEntry("parseError", "true")
                    .containsEntry("source", "jsatl12-jt-message")
                    .containsEntry("identityResolved", "false")
                    .containsEntry("identitySource", "UNKNOWN");
            assertThat(passthrough.data()).containsExactly(raw);
        });
    }

    @Test
    void archiveFailureProducesPassthroughEvent() {
        Jsatl12ArchiveEventHandler handler = new Jsatl12ArchiveEventHandler();
        byte[] raw = new byte[]{0x30, 0x31, 0x63, 0x64, 0, 0, 0, 1, 0x7f};
        Jsatl12ArchiveFailure failure = new Jsatl12ArchiveFailure(
                raw,
                "jsatl12/2026/06/22/peer/file.bin",
                1,
                "10.0.0.8:7612",
                "archive backend unavailable",
                Instant.parse("2026-06-22T01:02:03Z"));

        List<VehicleEvent> events = handler.onArchiveFailure(failure);

        assertThat(events).singleElement().satisfies(event -> {
            assertThat(event).isInstanceOf(VehicleEvent.Passthrough.class);
            VehicleEvent.Passthrough passthrough = (VehicleEvent.Passthrough) event;
            assertThat(passthrough.source()).isEqualTo(ProtocolId.JSATL12);
            assertThat(passthrough.vin()).isEqualTo("unknown");
            assertThat(passthrough.eventTime()).isEqualTo(Instant.parse("2026-06-22T01:02:03Z"));
            assertThat(passthrough.data()).containsExactly(raw);
            assertThat(passthrough.metadata())
                    .containsEntry("vin", "unknown")
                    .containsEntry("archiveError", "true")
                    .containsEntry("archiveKey", "jsatl12/2026/06/22/peer/file.bin")
                    .containsEntry("chunkSizeBytes", "1")
                    .containsEntry("identityResolved", "false")
                    .containsEntry("identitySource", "UNKNOWN");
        });
    }

    @Test
    void malformedFrameProducesPassthroughEvent() {
        Jsatl12ArchiveEventHandler handler = new Jsatl12ArchiveEventHandler();
        byte[] raw = new byte[]{0x30, 0x31, 0x63, 0x64, 0, 0, 0, 3, 0x01, 0x02, 0x03};
        Jsatl12MalformedFrame malformed = new Jsatl12MalformedFrame(
                raw,
                "10.0.0.8:7612",
                "malformed jsatl12 frame",
                Instant.parse("2026-06-22T01:02:03Z"));

        List<VehicleEvent> events = handler.onMalformedFrame(malformed);

        assertThat(events).singleElement().satisfies(event -> {
            assertThat(event).isInstanceOf(VehicleEvent.Passthrough.class);
            VehicleEvent.Passthrough passthrough = (VehicleEvent.Passthrough) event;
            assertThat(passthrough.source()).isEqualTo(ProtocolId.JSATL12);
            assertThat(passthrough.vin()).isEqualTo("unknown");
            assertThat(passthrough.eventTime()).isEqualTo(Instant.parse("2026-06-22T01:02:03Z"));
            assertThat(passthrough.data()).containsExactly(raw);
            assertThat(passthrough.metadata())
                    .containsEntry("vin", "unknown")
                    .containsEntry("peer", "10.0.0.8:7612")
                    .containsEntry("source", "jsatl12-frame")
                    .containsEntry("frameError", "true")
                    .containsEntry("frameErrorMessage", "malformed jsatl12 frame")
                    .containsEntry("parseError", "true")
                    .containsEntry("parseErrorMessage", "malformed jsatl12 frame")
                    .containsEntry("identityResolved", "false")
                    .containsEntry("identitySource", "UNKNOWN");
        });
    }
}
