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

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;

/**
 * 广东燃料电池汽车示范应用城市群综合监管平台 §7.2.3.4 表 13/14：燃料电池电堆数据。
 *
 * <p>typeCode {@code 0x30}，工程上观察到对端在 GB/T 32960.3-<b>2016</b> 帧（{@code 2323}
 * 起始符）里下发该块。本规范在 GB/T 32960.3-2016 标准里属于 {@code 0x30~0x7F} 预留区段，
 * 因此只有当对端被 vendor profile 选中后才启用此 parser。
 *
 * <p>结构：
 * <pre>
 *   stackCount (1B)
 *   For each stack:
 *     engineWorkState (1B)                         00 关闭 / 01 打开 / FE 异常 / FF 无效
 *     stackWaterOutletTempC (1B, -40 offset)
 *     hydrogenInletPressureKpa (2B WORD, -100 offset, 0.1 kPa)
 *     airInletPressureKpa (2B WORD, -100 offset, 0.1 kPa)
 *     airInletTempC (1B, -40 offset)
 *     maxCellVoltageId (2B WORD)
 *     minCellVoltageId (2B WORD)
 *     maxCellVoltageV (2B WORD, 0.001 V)
 *     minCellVoltageV (2B WORD, 0.001 V)
 *     avgCellVoltageV (2B WORD, 0.001 V)
 *     cellCount (2B WORD)
 *     frameCellStart (2B WORD)
 *     frameCellCount (1B)
 *     frameCellVoltagesV (2 * frameCellCount, 0.001 V)
 * </pre>
 */
public final class GdFcStackBlockParser implements InfoBlockParser {

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

    @Override
    public InfoBlock parse(ByteBuffer buf) {
        int stackCount = buf.get() & 0xFF;
        List<InfoBlock.GuangdongFc.Stack.Item> stacks = new ArrayList<>(stackCount);
        for (int i = 0; i < stackCount; i++) {
            Integer workState = ValueDecoder.u8raw(buf);
            Integer waterTemp = ValueDecoder.tempOffset40(buf);
            Double h2InletP = ValueDecoder.scaledU16WithOffset(buf, 0.1, -100.0);
            Double airInletP = ValueDecoder.scaledU16WithOffset(buf, 0.1, -100.0);
            Integer airInletTemp = ValueDecoder.tempOffset40(buf);
            Integer maxId = ValueDecoder.u16(buf);
            Integer minId = ValueDecoder.u16(buf);
            Double maxV = ValueDecoder.scaledU16(buf, 0.001);
            Double minV = ValueDecoder.scaledU16(buf, 0.001);
            Double avgV = ValueDecoder.scaledU16(buf, 0.001);
            Integer cellCount = ValueDecoder.u16(buf);
            Integer frameStart = ValueDecoder.u16(buf);
            int frameCells = buf.get() & 0xFF;
            List<Double> frameVoltages = new ArrayList<>(frameCells);
            // 对端会把单体电压按 frameCellStart/frameCellCount 分帧上送；这里只解析当前帧片段，
            // 完整电压数组由查询层按同一 vin+eventTime 合并，避免入站侧持有跨帧状态。
            int safe = Math.min(frameCells, buf.remaining() / 2);
            for (int k = 0; k < safe; k++) {
                frameVoltages.add((buf.getShort() & 0xFFFF) * 0.001);
            }
            stacks.add(new InfoBlock.GuangdongFc.Stack.Item(
                    workState, waterTemp, h2InletP, airInletP, airInletTemp,
                    maxId, minId, maxV, minV, avgV,
                    cellCount, frameStart, frameCells, frameVoltages));
        }
        return new InfoBlock.GuangdongFc.Stack(stackCount, stacks);
    }
}
