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

import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;

class Jsatl12AttachmentTrackerTest {

    @Test
    void completionAckRequestsOnlyMissingRangesUntilFileIsComplete() {
        Jsatl12AttachmentTracker tracker = new Jsatl12AttachmentTracker();
        String phone = "13800138000";
        String fileName = "ADAS_001.jpg";

        tracker.registerAttachmentList(phone, t1210Body(fileName, 6));
        tracker.recordDataPacket(phone, dataPacket(fileName, 0, new byte[]{0x01, 0x02, 0x03}));

        Jsatl12UploadCompletionAck first = tracker.completeUpload(phone, t1212Body(fileName, 2, 6));

        assertThat(first.name()).isEqualTo(fileName);
        assertThat(first.type()).isEqualTo(2);
        assertThat(first.result()).isEqualTo(1);
        assertThat(first.missingRanges()).containsExactly(new Jsatl12UploadCompletionAck.Range(3, 3));

        tracker.recordDataPacket(phone, dataPacket(fileName, 3, new byte[]{0x04, 0x05, 0x06}));

        Jsatl12UploadCompletionAck second = tracker.completeUpload(phone, t1212Body(fileName, 2, 6));

        assertThat(second.result()).isZero();
        assertThat(second.missingRanges()).isEmpty();
        assertThat(tracker.knownFiles(phone)).doesNotContain(fileName);
    }

    @Test
    void dataPacketCanBeParsedFromProductionLayout() {
        Jsatl12DataPacket packet = Jsatl12DataPacket.parse(dataPacket("BSD_002.bin", 12, new byte[]{0x01, 0x02}));

        assertThat(packet.name()).isEqualTo("BSD_002.bin");
        assertThat(packet.offset()).isEqualTo(12);
        assertThat(packet.length()).isEqualTo(2);
        assertThat(packet.data()).containsExactly(0x01, 0x02);
    }

    private static byte[] t1210Body(String fileName, long size) {
        byte[] name = fileName.getBytes(StandardCharsets.US_ASCII);
        byte[] out = new byte[57 + 1 + name.length + 4];
        putAscii(out, 0, 7, "DEV0001");
        putAscii(out, 7, 7, "DEV0001");
        out[13] = 0x26;
        out[14] = 0x06;
        out[15] = 0x22;
        out[16] = 0x10;
        out[17] = 0x30;
        out[18] = 0x45;
        out[19] = 0x01;
        out[20] = 0x01;
        putAscii(out, 23, 32, "ALARM-NO-001");
        out[55] = 0;
        out[56] = 1;
        out[57] = (byte) name.length;
        System.arraycopy(name, 0, out, 58, name.length);
        writeDword(out, 58 + name.length, size);
        return out;
    }

    private static byte[] t1212Body(String fileName, int type, long size) {
        byte[] name = fileName.getBytes(StandardCharsets.US_ASCII);
        byte[] out = new byte[1 + name.length + 1 + 4];
        out[0] = (byte) name.length;
        System.arraycopy(name, 0, out, 1, name.length);
        out[1 + name.length] = (byte) type;
        writeDword(out, 2 + name.length, size);
        return out;
    }

    private static byte[] dataPacket(String name, int offset, byte[] data) {
        byte[] out = new byte[62 + data.length];
        out[0] = 0x30;
        out[1] = 0x31;
        out[2] = 0x63;
        out[3] = 0x64;
        putAscii(out, 4, 50, name);
        writeDword(out, 54, offset);
        writeDword(out, 58, data.length);
        System.arraycopy(data, 0, out, 62, data.length);
        return out;
    }

    private static void putAscii(byte[] out, int offset, int len, String value) {
        byte[] bytes = value.getBytes(StandardCharsets.US_ASCII);
        System.arraycopy(bytes, 0, out, offset, Math.min(bytes.length, len));
    }

    private static void writeDword(byte[] out, int offset, long value) {
        out[offset] = (byte) ((value >>> 24) & 0xFF);
        out[offset + 1] = (byte) ((value >>> 16) & 0xFF);
        out[offset + 2] = (byte) ((value >>> 8) & 0xFF);
        out[offset + 3] = (byte) (value & 0xFF);
    }
}
