package com.lingniu.ingest.protocol.gb32960.codec.parser.v2025;

import com.lingniu.ingest.protocol.gb32960.codec.InfoBlockParser;
import com.lingniu.ingest.protocol.gb32960.codec.ValueDecoder;
import com.lingniu.ingest.protocol.gb32960.model.InfoBlock;
import com.lingniu.ingest.protocol.gb32960.model.ProtocolVersion;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * 报警数据 (0x06) —— GB/T 32960.3-2025 §7.2.4.9 表 23。变长。
 * 前半部分与 2016 版相同，尾部新增"通用报警故障总数(1) + N5×(flagBit(1)+level(1))"。
 */
public final class AlarmV2025BlockParser implements InfoBlockParser {

    @Override public ProtocolVersion version() { return ProtocolVersion.V2025; }
    @Override public int typeCode() { return 0x06; }
    @Override public int fixedLength() { return -1; }

    @Override
    public InfoBlock parse(ByteBuffer buf) {
        Integer maxLevel = ValueDecoder.u8(buf);
        long generalFlag = ValueDecoder.u32raw(buf);
        List<Long> battery = readFaultList(buf);
        List<Long> motor = readFaultList(buf);
        List<Long> engine = readFaultList(buf);
        List<Long> other = readFaultList(buf);

        int generalAlarmCount = buf.hasRemaining() ? (buf.get() & 0xFF) : 0;
        List<InfoBlock.Gb32960V2025.Alarm.GeneralAlarmEntry> levels = new ArrayList<>(generalAlarmCount);
        // 2025 新增通用报警等级列表；尾部不完整时保留已读条目，避免整帧丢弃。
        for (int i = 0; i < generalAlarmCount && buf.remaining() >= 2; i++) {
            int bit = buf.get() & 0xFF;
            int level = buf.get() & 0xFF;
            levels.add(new InfoBlock.Gb32960V2025.Alarm.GeneralAlarmEntry(bit, level));
        }

        return new InfoBlock.Gb32960V2025.Alarm(
                maxLevel, generalFlag, battery, motor, engine, other, levels);
    }

    private static List<Long> readFaultList(ByteBuffer buf) {
        int count = buf.get() & 0xFF;
        List<Long> out = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            // 故障码按 4 字节无符号值处理，避免高位为 1 时变成负数。
            out.add(buf.getInt() & 0xFFFFFFFFL);
        }
        return out;
    }
}
