package com.lingniu.ingest.protocol.gb32960.codec.parser.vendor.guangdong;

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

import java.nio.ByteBuffer;

/**
 * 广东燃料电池 peer 的厂商私有 TLV 块兜底 parser。
 *
 * <p>同一 peer 在广东规范 v1.0 表 8 列出的 0x30~0x34 / 0x80 之外，**还会下发**一些
 * 在该规范里完全未定义的扩展 typeCode（线上首先观察到 {@code 0x83}，未来不排除有
 * 0x84 等）。这些块经验上是 **TLV 格式**：
 *
 * <pre>
 *   typeCode (1B, 由 BodyParser 外层消费)
 *   length   (2B WORD, 大端)
 *   payload  (length 字节)
 * </pre>
 *
 * <p>本 parser 严格按 length 消费字节，<b>不</b>贪心读到 buffer 末尾，保证 BodyParser
 * 主循环在该块之后仍能继续解析后面的标准/扩展块。
 *
 * <p>typeCode 通过构造器注入，未来若发现新的 vendor typeCode，只需在 catalog 里多注册
 * 一个 {@code new GdFcVendorTlvBlockParser(0x84)} 即可，无需新写 parser 类。
 *
 * <p>length 字段宽度为 2 字节是从 {@code 0x83} 实际字节序列推断而来（0x0024=36 与
 * payload 实际长度匹配）；如未来对端的某个 typeCode 用 1B length 而非 2B，将出现
 * 字节漂移并被 BodyParser 的 hex dump 立刻暴露，可针对性新增独立 parser。
 */
public final class GdFcVendorTlvBlockParser implements InfoBlockParser {

    private final int typeCode;

    public GdFcVendorTlvBlockParser(int typeCode) {
        if (typeCode < 0 || typeCode > 0xFF) {
            throw new IllegalArgumentException("typeCode out of range: " + typeCode);
        }
        this.typeCode = typeCode;
    }

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

    @Override
    public InfoBlock parse(ByteBuffer buf) {
        int len = buf.getShort() & 0xFFFF;
        // 防御：若 length 大于剩余可读字节，截短到剩余长度（避免 BufferUnderflowException）
        // declaredLength 仍保留原值，后续可以在 API/日志里看出对端长度声明是否异常。
        int safe = Math.min(len, buf.remaining());
        byte[] payload = new byte[safe];
        buf.get(payload);
        return new InfoBlock.GuangdongFc.VendorTlv(typeCode, len, payload);
    }
}
