package com.cmvr.quic.gateway.protocol;

import io.netty.buffer.ByteBuf;

import java.util.ArrayList;
import java.util.List;

/** 解析“4字节大端长度 + Protobuf负载”的可靠控制流。 */
public final class ControlFrameDecoder {

    private static final int LENGTH_FIELD_BYTES = 4;

    private final int maximumPayloadBytes;
    private byte[] buffer = new byte[4096];
    private int readableBytes;

    public ControlFrameDecoder(int maximumPayloadBytes) {
        if (maximumPayloadBytes <= 0) {
            throw new IllegalArgumentException("maximumPayloadBytes必须大于0");
        }
        this.maximumPayloadBytes = maximumPayloadBytes;
    }

    public List<byte[]> append(ByteBuf source) {
        int incoming = source.readableBytes();
        if (incoming == 0) {
            return new ArrayList<byte[]>(0);
        }
        if ((long) readableBytes + incoming > (long) maximumPayloadBytes + LENGTH_FIELD_BYTES) {
            throw new IllegalArgumentException("控制流累积数据超过配置上限");
        }
        ensureCapacity(readableBytes + incoming);
        source.readBytes(buffer, readableBytes, incoming);
        readableBytes += incoming;

        List<byte[]> frames = new ArrayList<byte[]>();
        int offset = 0;
        while (readableBytes - offset >= LENGTH_FIELD_BYTES) {
            long length = ((long) (buffer[offset] & 0xff) << 24)
                    | ((long) (buffer[offset + 1] & 0xff) << 16)
                    | ((long) (buffer[offset + 2] & 0xff) << 8)
                    | (long) (buffer[offset + 3] & 0xff);
            if (length == 0 || length > maximumPayloadBytes) {
                throw new IllegalArgumentException("控制帧长度不合法: " + length);
            }
            long completeBytes = LENGTH_FIELD_BYTES + length;
            if (readableBytes - offset < completeBytes) {
                break;
            }
            byte[] payload = new byte[(int) length];
            System.arraycopy(buffer, offset + LENGTH_FIELD_BYTES, payload, 0, payload.length);
            frames.add(payload);
            offset += (int) completeBytes;
        }
        if (offset > 0) {
            readableBytes -= offset;
            System.arraycopy(buffer, offset, buffer, 0, readableBytes);
        }
        return frames;
    }

    private void ensureCapacity(int required) {
        if (required <= buffer.length) {
            return;
        }
        int capacity = buffer.length;
        while (capacity < required) {
            capacity = Math.min(maximumPayloadBytes + LENGTH_FIELD_BYTES, capacity << 1);
            if (capacity < required && capacity == maximumPayloadBytes + LENGTH_FIELD_BYTES) {
                throw new IllegalArgumentException("控制帧缓冲区无法扩容");
            }
        }
        byte[] expanded = new byte[capacity];
        System.arraycopy(buffer, 0, expanded, 0, readableBytes);
        buffer = expanded;
    }
}
