package com.lingniu.ingest.protocol.gb32960.model;

import java.nio.ByteBuffer;

/**
 * 实时信息的车端数字签名（GB/T 32960.3-2025 表 8）。
 *
 * <p>签名信息出现在实时上报数据单元的末尾，紧跟在信息体循环后，由 {@code 0xFF}
 * 作为"签名数据开始标识"引出（见表 9）。签名范围：从数据采集时间的第一字节到签名
 * 信息前一个字节的数字签名。
 *
 * <p>表 8 字段：
 * <pre>
 *   signType(1)    签名类型：0x01 SM2 / 0x02 RSA / 0x03 ECC，其他预留
 *   rLen(2 WORD)   签名 R 值长度
 *   r(rLen)        签名 R 值
 *   sLen(2 WORD)   签名 S 值长度
 *   s(sLen)        签名 S 值
 * </pre>
 */
public record SignatureInfo(SignType signType, byte[] r, byte[] s) {

    public enum SignType {
        /** 0x01：SM2 国密签名。 */
        SM2(0x01),
        /** 0x02：RSA 签名。 */
        RSA(0x02),
        /** 0x03：ECC 签名。 */
        ECC(0x03),
        /** 其他预留。 */
        UNKNOWN(0xFF);

        private final int code;
        SignType(int code) { this.code = code; }
        public int code() { return code; }

        public static SignType of(int code) {
            for (SignType t : values()) if (t.code == code) return t;
            return UNKNOWN;
        }
    }

    /**
     * 尝试解析签名字节。非法数据时返回 null 并保留原始字节由冷存分析。
     *
     * @param bytes 签名原始字节（不含前缀的 0xFF 签名开始标识）
     */
    public static SignatureInfo tryParse(byte[] bytes) {
        if (bytes == null || bytes.length < 5) return null;
        ByteBuffer buf = ByteBuffer.wrap(bytes);
        try {
            SignType type = SignType.of(buf.get() & 0xFF);
            int rLen = buf.getShort() & 0xFFFF;
            if (rLen > buf.remaining() - 2) return null;
            byte[] r = new byte[rLen];
            buf.get(r);
            int sLen = buf.getShort() & 0xFFFF;
            if (sLen > buf.remaining()) return null;
            byte[] s = new byte[sLen];
            buf.get(s);
            return new SignatureInfo(type, r, s);
        } catch (Exception e) {
            return null;
        }
    }
}
