package com.foxx.androidcast.network.transport.fec;

/*********************************************************************
 * FecShardReassemblyTest.java
 * Created at: Mon 18 May 2026 14:25:02 +0200
 * Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
 * Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
 * class FecShardReassemblyTest
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (3 commits, 88 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	8a2b4ed355ddde76f87acb9d6e990d03711ae10aa1d3d87b86e8d4f02ba1b6fe
**********************************************************************/
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class FecShardReassemblyTest {
    @Test
    public void perShardDelivery_recoversOneLoss() throws Exception {
        byte[] payload = new byte[512];
        for (int i = 0; i < payload.length; i++) {
            payload[i] = (byte) (i & 0xFF);
        }
        ReedSolomonFec fec = new ReedSolomonFec(4, 3);
        byte[][] shards = fec.encode(payload);
        int groupId = 7;
        int baseId = 500;
        FecShardReassembly asm = null;
        for (int i = 0; i < shards.length; i++) {
            if (i == 1) {
                continue;
            }
            byte[] wire = FecShardWire.encodeShard(
                    ProtectionEnvelope.MODE_FEC_34, groupId, baseId, i, shards.length,
                    payload.length, 4, 3, shards[i]);
            FecShardWire.Parsed p = FecShardWire.tryParse(wire);
            assertNotNull(p);
            if (asm == null) {
                asm = new FecShardReassembly(p);
            }
            assertTrue(asm.addShard(p));
        }
        assertNotNull(asm);
        byte[] recovered = asm.tryDecode();
        assertNotNull(recovered);
        assertArrayEquals(payload, recovered);
    }

    @Test
    public void vp9SizedPayload_recoversAllShards() throws Exception {
        byte[] payload = new byte[54_000];
        for (int i = 0; i < payload.length; i++) {
            payload[i] = (byte) (i & 0xFF);
        }
        ReedSolomonFec fec = new ReedSolomonFec(4, 3);
        byte[][] shards = fec.encode(payload);
        FecShardReassembly asm = null;
        for (int i = 0; i < shards.length; i++) {
            byte[] wire = FecShardWire.encodeShard(
                    ProtectionEnvelope.MODE_FEC_34, 42, 900, i, shards.length,
                    payload.length, 4, 3, shards[i]);
            FecShardWire.Parsed p = FecShardWire.tryParse(wire);
            assertNotNull(p);
            if (asm == null) {
                asm = new FecShardReassembly(p);
            }
            assertTrue(asm.addShard(p));
        }
        byte[] recovered = asm.tryDecode();
        assertNotNull(recovered);
        assertArrayEquals(payload, recovered);
    }

    @Test
    public void insufficientShards_returnsNull() throws Exception {
        byte[] payload = new byte[] {1, 2, 3, 4, 5};
        ReedSolomonFec fec = new ReedSolomonFec(4, 3);
        byte[][] shards = fec.encode(payload);
        byte[] wire = FecShardWire.encodeShard(
                ProtectionEnvelope.MODE_FEC_34, 1, 10, 0, shards.length,
                payload.length, 4, 3, shards[0]);
        FecShardWire.Parsed p = FecShardWire.tryParse(wire);
        assertNotNull(p);
        FecShardReassembly asm = new FecShardReassembly(p);
        assertTrue(asm.addShard(p));
        assertNull(asm.tryDecode());
    }
}
