package com.lingniu.ingest.protocol.jt1078;

import com.lingniu.ingest.protocol.jt1078.media.Jt1078MalformedRtpPacket;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078RtpPacket;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078ReceivedRtpPacket;
import com.lingniu.ingest.protocol.jt1078.media.Jt1078UdpRtpPacketDecoder;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.channel.socket.DatagramPacket;
import org.junit.jupiter.api.Test;

import java.net.InetSocketAddress;

import static org.assertj.core.api.Assertions.assertThat;

class Jt1078UdpRtpPacketDecoderTest {

    @Test
    void decodesSingleUdpDatagramRtpPacket() {
        EmbeddedChannel channel = new EmbeddedChannel(new Jt1078UdpRtpPacketDecoder(1024));
        InetSocketAddress sender = new InetSocketAddress("127.0.0.1", 19000);
        InetSocketAddress recipient = new InetSocketAddress("127.0.0.1", 10780);

        channel.writeInbound(new DatagramPacket(Unpooled.wrappedBuffer(Jt1078RtpPacketDecoderTest.packet(
                9, "013800138000", 4, 0, 2, 123456789L, new byte[]{5, 6, 7})), recipient, sender));

        Jt1078ReceivedRtpPacket received = channel.readInbound();
        Jt1078RtpPacket decoded = received.packet();
        assertThat(received.peer()).isEqualTo("127.0.0.1:19000");
        assertThat(decoded.sequence()).isEqualTo(9);
        assertThat(decoded.sim()).isEqualTo("013800138000");
        assertThat(decoded.channelId()).isEqualTo(4);
        assertThat(decoded.packetType()).isEqualTo(2);
        assertThat(decoded.payload()).containsExactly(5, 6, 7);
    }

    @Test
    void shortUdpDatagramEmitsMalformedCandidateWithPeerAndRawBytes() {
        EmbeddedChannel channel = new EmbeddedChannel(new Jt1078UdpRtpPacketDecoder(1024));
        InetSocketAddress sender = new InetSocketAddress("127.0.0.1", 19000);
        InetSocketAddress recipient = new InetSocketAddress("127.0.0.1", 10780);

        channel.writeInbound(new DatagramPacket(Unpooled.wrappedBuffer(new byte[]{1, 2, 3}), recipient, sender));

        Jt1078MalformedRtpPacket malformed = channel.readInbound();
        assertThat(malformed.transport()).isEqualTo("udp");
        assertThat(malformed.peer()).isEqualTo("127.0.0.1:19000");
        assertThat(malformed.reason()).contains("too short");
        assertThat(malformed.rawBytes()).containsExactly(1, 2, 3);
        assertThat(malformed.packetLength()).isEqualTo(3);
    }

    @Test
    void invalidUdpDatagramEmitsMalformedCandidateInsteadOfThrowing() {
        EmbeddedChannel channel = new EmbeddedChannel(new Jt1078UdpRtpPacketDecoder(1024));
        InetSocketAddress sender = new InetSocketAddress("127.0.0.1", 19000);
        InetSocketAddress recipient = new InetSocketAddress("127.0.0.1", 10780);
        byte[] invalid = Jt1078RtpPacketDecoderTest.packet(
                9, "013800138000", 4, 0, 2, 123456789L, new byte[]{5, 6, 7});
        invalid[0] = 0x12;

        channel.writeInbound(new DatagramPacket(Unpooled.wrappedBuffer(invalid), recipient, sender));

        Jt1078MalformedRtpPacket malformed = channel.readInbound();
        assertThat(malformed.transport()).isEqualTo("udp");
        assertThat(malformed.peer()).isEqualTo("127.0.0.1:19000");
        assertThat(malformed.reason()).contains("invalid magic");
        assertThat(malformed.rawBytes()).containsExactly(invalid);
        assertThat(malformed.packetLength()).isEqualTo(invalid.length);
    }

    @Test
    void oversizedUdpDatagramKeepsSimForIdentityResolution() {
        EmbeddedChannel channel = new EmbeddedChannel(new Jt1078UdpRtpPacketDecoder(30));
        InetSocketAddress sender = new InetSocketAddress("127.0.0.1", 19000);
        InetSocketAddress recipient = new InetSocketAddress("127.0.0.1", 10780);
        byte[] oversized = Jt1078RtpPacketDecoderTest.packet(
                10, "013800138000", 4, 0, 2, 123456789L, new byte[]{5, 6, 7, 8});

        channel.writeInbound(new DatagramPacket(Unpooled.wrappedBuffer(oversized), recipient, sender));

        Jt1078MalformedRtpPacket malformed = channel.readInbound();
        assertThat(malformed.transport()).isEqualTo("udp");
        assertThat(malformed.sim()).isEqualTo("013800138000");
        assertThat(malformed.reason()).contains("too large");
        assertThat(malformed.rawBytes()).containsExactly(oversized);
        assertThat(malformed.packetLength()).isEqualTo(oversized.length);
    }
}
