package com.lingniu.ingest.protocol.jt1078.media;

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

import java.time.Instant;
import java.util.List;

/**
 * JT/T 1078 TCP RTP 包解码器。
 *
 * <p>包头固定魔数 0x30316364，header 固定 28 字节，随后是 bodyLength 指定的媒体负载。
 */
public final class Jt1078RtpPacketDecoder extends ByteToMessageDecoder {

    private final int maxPacketLength;

    public Jt1078RtpPacketDecoder(int maxPacketLength) {
        this.maxPacketLength = maxPacketLength;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        while (true) {
            if (in.readableBytes() < Jt1078RtpPacketParser.HEADER_LEN) {
                return;
            }
            int frameStart = findMagic(in);
            if (frameStart < 0) {
                in.skipBytes(Math.max(0, in.readableBytes() - 3));
                return;
            }
            if (frameStart > in.readerIndex()) {
                in.skipBytes(frameStart - in.readerIndex());
            }
            if (in.readableBytes() < Jt1078RtpPacketParser.HEADER_LEN) {
                return;
            }
            int length = in.getUnsignedShort(in.readerIndex() + 26);
            int packetLength = Jt1078RtpPacketParser.HEADER_LEN + length;
            if (packetLength > maxPacketLength) {
                String sim = Jt1078RtpPacketParser.peekSim(in);
                int available = in.readableBytes();
                int rawLength = Math.min(available, packetLength);
                byte[] raw = new byte[rawLength];
                in.readBytes(raw);
                out.add(new Jt1078MalformedRtpPacket(
                        "tcp",
                        peer(ctx),
                        sim,
                        raw,
                        packetLength,
                        "jt1078 rtp packet too large: " + packetLength,
                        Instant.now()));
                return;
            }
            if (in.readableBytes() < packetLength) {
                return;
            }
            ByteBuf packet = in.readSlice(packetLength);
            out.add(Jt1078RtpPacketParser.parse(packet));
        }
    }

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

    private static int findMagic(ByteBuf in) {
        int start = in.readerIndex();
        int end = in.writerIndex() - 3;
        for (int i = start; i < end; i++) {
            if (in.getInt(i) == Jt1078RtpPacketParser.MAGIC) {
                return i;
            }
        }
        return -1;
    }
}
