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

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;

/**
 * 可充电储能装置电压数据 (0x08) —— GB/T 32960.3-2016 表 B.18。变长。
 * subSystemCount(1) + 每子系统 [batteryIndex(1) + voltage(2,0.1V) + current(2,0.1A,offset -1000)
 *   + cellCount(2) + frameCellStart(2) + frameCellCount(1) + cellVoltages(frameCellCount*2,0.001V)]。
 *
 * <p>PoC 汇总：保留子系统数 + 总电压 + 单体最高/最低值。
 * 2025 版 0x08 语义已变更为动力蓄电池温度。
 */
public final class VoltageV2016BlockParser implements InfoBlockParser {

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

    @Override
    public InfoBlock parse(ByteBuffer buf) {
        int subCount = buf.get() & 0xFF;
        double totalV = 0;
        double maxCell = Double.MIN_VALUE;
        double minCell = Double.MAX_VALUE;
        for (int i = 0; i < subCount; i++) {
            buf.get(); // batteryIndex
            double voltage = (buf.getShort() & 0xFFFF) * 0.1;
            totalV += voltage;
            buf.getShort(); // current (skip)
            int cellCount = buf.getShort() & 0xFFFF;
            buf.getShort(); // frameCellStart
            int frameCellCount = buf.get() & 0xFF;
            // 报文可能只上传本帧范围内的单体电压；聚合层只保存最高/最低/总压摘要。
            int actual = Math.min(frameCellCount, cellCount);
            for (int c = 0; c < actual; c++) {
                double cellV = (buf.getShort() & 0xFFFF) * 0.001;
                if (cellV > maxCell) maxCell = cellV;
                if (cellV < minCell) minCell = cellV;
            }
            // 如果 frameCellCount 大于 cellCount，剩余字节仍要消费掉，避免影响后续子系统解析。
            for (int c = actual; c < frameCellCount; c++) buf.getShort();
        }
        if (maxCell == Double.MIN_VALUE) maxCell = 0;
        if (minCell == Double.MAX_VALUE) minCell = 0;
        return new InfoBlock.Gb32960V2016.Voltage(subCount, maxCell, minCell, totalV);
    }
}
