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

import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.annotation.EventEmit;
import com.lingniu.ingest.api.annotation.MessageMapping;
import com.lingniu.ingest.api.annotation.ProtocolHandler;
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 com.lingniu.ingest.protocol.jsatl12.inbound.Jsatl12MessageId;

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

@ProtocolHandler(protocol = ProtocolId.JSATL12)
public final class Jsatl12ArchiveEventHandler {

    @MessageMapping(command = Jsatl12MessageId.DATA_CHUNK_ARCHIVED, desc = "主动安全附件数据块已归档")
    @EventEmit(VehicleEvent.MediaMeta.class)
    public List<VehicleEvent> onDataChunkArchived(Jsatl12ArchivedChunk chunk) {
        Instant eventTime = chunk.archivedAt() == null ? Instant.now() : chunk.archivedAt();
        String peer = chunk.peer() == null || chunk.peer().isBlank() ? "unknown" : chunk.peer();
        return List.of(new VehicleEvent.MediaMeta(
                UUID.randomUUID().toString(),
                nullToUnknown(chunk.vin()),
                ProtocolId.JSATL12,
                eventTime,
                Instant.now(),
                null,
                baseMeta(
                        "vin", nullToUnknown(chunk.vin()),
                        "phone", nullToEmpty(chunk.phone()),
                        "identityResolved", Boolean.toString(chunk.identityResolved()),
                        "identitySource", nullToEmpty(chunk.identitySource()),
                        "peer", peer,
                        "archiveKey", nullToEmpty(chunk.archiveKey()),
                        "archiveRef", nullToEmpty(chunk.archiveRef()),
                        "fileName", nullToEmpty(chunk.fileName()),
                        "fileOffset", Long.toString(Math.max(0, chunk.fileOffset())),
                        "declaredChunkSizeBytes", Long.toString(Math.max(0, chunk.declaredSizeBytes())),
                        "chunkSizeBytes", Long.toString(Math.max(0, chunk.sizeBytes()))),
                "jsatl12-" + peer + "-" + eventTime.toEpochMilli(),
                "jsatl12-data-chunk",
                Math.max(0, chunk.sizeBytes()),
                nullToEmpty(chunk.archiveRef())));
    }

    @MessageMapping(command = Jsatl12MessageId.MALFORMED_JT_MESSAGE, desc = "主动安全 JT 消息解析失败兜底")
    @EventEmit(VehicleEvent.Passthrough.class)
    public List<VehicleEvent> onMalformedJtMessage(Jsatl12MalformedJtMessage malformed) {
        Instant eventTime = malformed.receivedAt() == null ? Instant.now() : malformed.receivedAt();
        String peer = malformed.peer() == null || malformed.peer().isBlank() ? "unknown" : malformed.peer();
        return List.of(new VehicleEvent.Passthrough(
                UUID.randomUUID().toString(),
                "unknown",
                ProtocolId.JSATL12,
                eventTime,
                Instant.now(),
                null,
                baseMeta(
                        "peer", peer,
                        "source", "jsatl12-jt-message",
                        "parseError", "true",
                        "parseErrorMessage", nullToEmpty(malformed.errorMessage())),
                Jsatl12MessageId.MALFORMED_JT_MESSAGE,
                malformed.rawBytes() == null ? new byte[0] : malformed.rawBytes()));
    }

    @MessageMapping(command = Jsatl12MessageId.DATA_CHUNK_ARCHIVE_FAILED, desc = "主动安全附件数据块归档失败兜底")
    @EventEmit(VehicleEvent.Passthrough.class)
    public List<VehicleEvent> onArchiveFailure(Jsatl12ArchiveFailure failure) {
        Instant eventTime = failure.failedAt() == null ? Instant.now() : failure.failedAt();
        String peer = failure.peer() == null || failure.peer().isBlank() ? "unknown" : failure.peer();
        return List.of(new VehicleEvent.Passthrough(
                UUID.randomUUID().toString(),
                "unknown",
                ProtocolId.JSATL12,
                eventTime,
                Instant.now(),
                null,
                baseMeta(
                        "peer", peer,
                        "source", "jsatl12-data-chunk",
                        "archiveError", "true",
                        "archiveErrorMessage", nullToEmpty(failure.errorMessage()),
                        "archiveKey", nullToEmpty(failure.archiveKey()),
                        "chunkSizeBytes", Long.toString(Math.max(0, failure.sizeBytes()))),
                Jsatl12MessageId.DATA_CHUNK_ARCHIVE_FAILED,
                failure.rawBytes() == null ? new byte[0] : failure.rawBytes()));
    }

    @MessageMapping(command = Jsatl12MessageId.MALFORMED_FRAME, desc = "主动安全附件帧边界异常兜底")
    @EventEmit(VehicleEvent.Passthrough.class)
    public List<VehicleEvent> onMalformedFrame(Jsatl12MalformedFrame malformed) {
        Instant eventTime = malformed.receivedAt() == null ? Instant.now() : malformed.receivedAt();
        String peer = malformed.peer() == null || malformed.peer().isBlank() ? "unknown" : malformed.peer();
        return List.of(new VehicleEvent.Passthrough(
                UUID.randomUUID().toString(),
                "unknown",
                ProtocolId.JSATL12,
                eventTime,
                Instant.now(),
                null,
                baseMeta(
                        "peer", peer,
                        "source", "jsatl12-frame",
                        "frameError", "true",
                        "frameErrorMessage", nullToEmpty(malformed.errorMessage()),
                        "parseError", "true",
                        "parseErrorMessage", nullToEmpty(malformed.errorMessage())),
                Jsatl12MessageId.MALFORMED_FRAME,
                malformed.rawBytes() == null ? new byte[0] : malformed.rawBytes()));
    }

    private static Map<String, String> baseMeta(String... kv) {
        java.util.HashMap<String, String> out = new java.util.HashMap<>();
        out.put("vin", "unknown");
        out.put("identityResolved", "false");
        out.put("identitySource", "UNKNOWN");
        for (int i = 0; i + 1 < kv.length; i += 2) {
            out.put(kv[i], kv[i + 1] == null ? "" : kv[i + 1]);
        }
        return Map.copyOf(out);
    }

    private static String nullToEmpty(String value) {
        return value == null ? "" : value;
    }

    private static String nullToUnknown(String value) {
        return value == null || value.isBlank() ? "unknown" : value;
    }
}
