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

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public record Jsatl12DataPacket(String name, long offset, long length, byte[] data) {

    private static final int HEADER_LENGTH = 62;

    public Jsatl12DataPacket {
        name = name == null ? "" : name.trim();
        data = data == null ? new byte[0] : Arrays.copyOf(data, data.length);
        if (offset < 0) {
            throw new IllegalArgumentException("jsatl12 data packet offset must not be negative");
        }
        if (length < 0) {
            throw new IllegalArgumentException("jsatl12 data packet length must not be negative");
        }
        if (length != data.length) {
            throw new IllegalArgumentException("jsatl12 data packet length " + length
                    + " does not match data length " + data.length);
        }
    }

    @Override
    public byte[] data() {
        return Arrays.copyOf(data, data.length);
    }

    public static Jsatl12DataPacket parse(byte[] bytes) {
        byte[] raw = bytes == null ? new byte[0] : bytes;
        if (raw.length < HEADER_LENGTH) {
            throw new IllegalArgumentException("jsatl12 data packet too short: " + raw.length);
        }
        if (raw[0] != 0x30 || raw[1] != 0x31 || raw[2] != 0x63 || raw[3] != 0x64) {
            throw new IllegalArgumentException("jsatl12 data packet magic mismatch");
        }
        String name = readFixedString(raw, 4, 50);
        long offset = readDword(raw, 54);
        long length = readDword(raw, 58);
        if (length > Integer.MAX_VALUE) {
            throw new IllegalArgumentException("jsatl12 data packet length too large: " + length);
        }
        if (raw.length < HEADER_LENGTH + (int) length) {
            throw new IllegalArgumentException("jsatl12 data packet body truncated: " + raw.length);
        }
        byte[] data = Arrays.copyOfRange(raw, HEADER_LENGTH, HEADER_LENGTH + (int) length);
        return new Jsatl12DataPacket(name, offset, length, data);
    }

    private static String readFixedString(byte[] raw, int offset, int length) {
        int end = offset;
        int max = Math.min(raw.length, offset + length);
        while (end < max && raw[end] != 0) {
            end++;
        }
        return new String(raw, offset, end - offset, StandardCharsets.UTF_8).trim();
    }

    static long readDword(byte[] raw, int offset) {
        return ((raw[offset] & 0xFFL) << 24)
                | ((raw[offset + 1] & 0xFFL) << 16)
                | ((raw[offset + 2] & 0xFFL) << 8)
                | (raw[offset + 3] & 0xFFL);
    }
}
