package com.lingniu.ingest.protocol.jt808.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * Netty 层 JT808 分帧 + 反转义。
 *
 * <p>寻找配对的 {@code 0x7e ... 0x7e}，提取中间字节并调用 {@link Jt808Escape#unescape} 还原，
 * 输出到 pipeline 的是 {@code byte[]}（反转义后的原始数据，不含首尾 0x7e）。
 */
public class Jt808FrameDecoder extends ByteToMessageDecoder {

    private static final int MAX_FRAME = 16 * 1024;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        while (in.readableBytes() >= 2) {
            int startIdx = in.indexOf(in.readerIndex(), in.writerIndex(), (byte) 0x7e);
            if (startIdx < 0) {
                int len = in.readableBytes();
                byte[] raw = new byte[len];
                in.readBytes(raw);
                out.add(new Jt808MalformedFrame(raw, peer(ctx), "jt808 missing frame boundary"));
                return;
            }
            if (startIdx != in.readerIndex()) {
                int len = startIdx - in.readerIndex();
                byte[] raw = new byte[len];
                in.readBytes(raw);
                out.add(new Jt808MalformedFrame(raw, peer(ctx), "jt808 leading bytes before frame boundary"));
            }
            int endIdx = in.indexOf(in.readerIndex() + 1, in.writerIndex(), (byte) 0x7e);
            if (endIdx < 0) {
                if (in.readableBytes() > MAX_FRAME) {
                    int len = in.readableBytes();
                    byte[] raw = new byte[len];
                    in.readBytes(raw);
                    out.add(new Jt808MalformedFrame(raw, peer(ctx), "jt808 unclosed frame too large: " + len));
                }
                return;
            }
            int rawLen = endIdx - (in.readerIndex() + 1);
            if (rawLen == 0) {
                // 两个相邻 0x7e：视作空帧，跳过一个
                in.skipBytes(1);
                continue;
            }
            byte[] raw = new byte[rawLen];
            in.skipBytes(1);
            in.readBytes(raw);
            in.skipBytes(1); // 结束 0x7e
            byte[] unescaped = Jt808Escape.unescape(raw, 0, raw.length);
            out.add(unescaped);
        }
    }

    private static String peer(ChannelHandlerContext ctx) {
        if (ctx == null || ctx.channel() == null || ctx.channel().remoteAddress() == null) {
            return "";
        }
        return ctx.channel().remoteAddress().toString();
    }
}
