package com.foxx.androidcast.network.transport;

/*********************************************************************
 * TransportLossStats.java
 * Created at: Sat 16 May 2026 18:50:36 +0200
 * Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
 * Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
 * class TransportLossStats
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (4 commits, 137 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	2d267619fa0169158e84e64613d7b891e0ca3e9fcdbb19c6cf747411a1a8ccf9
**********************************************************************/
/**
 * Per-transport loss / damage counters (UDP datagrams, reassembly, app-layer drops).
 * Thread-safe increments; copy for stats exchange.
 */
public final class TransportLossStats {
    public long datagramsSent;
    public long datagramsReceived;
    public long datagramsInvalid;
    public long fragmentsReceived;
    public long fragmentsDuplicate;
    public long reassemblyCompleted;
    public long reassemblyIncomplete;
    public long reassemblySuperseded;
    public long wirePacketsDropped;
    public long malformedPackets;

    public int sendDroppedVideoP;
    public int sendDroppedAudio;
    public int sendQueueDepth;

    public long recvVideoPackets;
    public long recvAudioPackets;
    public long recvVideoSkippedAwaitingKey;
    public long recvVideoDecodeErrors;
    public long recvAudioDecodeErrors;
    public long recvAudioQueueDrops;
    public long recvDamagedVideoFrames;

    public StreamProtectionMode protectionMode = StreamProtectionMode.NONE;
    public long fecPacketsEncoded;
    public long fecPacketsDecoded;
    public long fecDecodeFailures;
    public long nackRequestsSent;
    public long nackRequestsReceived;
    public long nackRetransmits;
    public long nackCacheMisses;
    /** Inbound FEC/protection payloads dropped (peer sent protection we did not negotiate). */
    public long unsupportedProtectionDropped;
    /** Legacy wire stats (mirrors real counters). */
    public long fecPacketsStub;
    public long nackRequestsStub;
    public long nackRetransmitsStub;

    public synchronized void addFrom(TransportLossStats other) {
        if (other == null) {
            return;
        }
        datagramsSent += other.datagramsSent;
        datagramsReceived += other.datagramsReceived;
        datagramsInvalid += other.datagramsInvalid;
        fragmentsReceived += other.fragmentsReceived;
        fragmentsDuplicate += other.fragmentsDuplicate;
        reassemblyCompleted += other.reassemblyCompleted;
        reassemblyIncomplete += other.reassemblyIncomplete;
        reassemblySuperseded += other.reassemblySuperseded;
        wirePacketsDropped += other.wirePacketsDropped;
        malformedPackets += other.malformedPackets;
        sendDroppedVideoP += other.sendDroppedVideoP;
        sendDroppedAudio += other.sendDroppedAudio;
        recvVideoPackets += other.recvVideoPackets;
        recvAudioPackets += other.recvAudioPackets;
        recvVideoSkippedAwaitingKey += other.recvVideoSkippedAwaitingKey;
        recvVideoDecodeErrors += other.recvVideoDecodeErrors;
        recvAudioDecodeErrors += other.recvAudioDecodeErrors;
        recvAudioQueueDrops += other.recvAudioQueueDrops;
        recvDamagedVideoFrames += other.recvDamagedVideoFrames;
        fecPacketsEncoded += other.fecPacketsEncoded;
        fecPacketsDecoded += other.fecPacketsDecoded;
        fecDecodeFailures += other.fecDecodeFailures;
        nackRequestsSent += other.nackRequestsSent;
        nackRequestsReceived += other.nackRequestsReceived;
        nackRetransmits += other.nackRetransmits;
        nackCacheMisses += other.nackCacheMisses;
        unsupportedProtectionDropped += other.unsupportedProtectionDropped;
        fecPacketsStub += other.fecPacketsStub;
        nackRequestsStub += other.nackRequestsStub;
        nackRetransmitsStub += other.nackRetransmitsStub;
    }

    public synchronized TransportLossStats copy() {
        TransportLossStats c = new TransportLossStats();
        c.datagramsSent = datagramsSent;
        c.datagramsReceived = datagramsReceived;
        c.datagramsInvalid = datagramsInvalid;
        c.fragmentsReceived = fragmentsReceived;
        c.fragmentsDuplicate = fragmentsDuplicate;
        c.reassemblyCompleted = reassemblyCompleted;
        c.reassemblyIncomplete = reassemblyIncomplete;
        c.reassemblySuperseded = reassemblySuperseded;
        c.wirePacketsDropped = wirePacketsDropped;
        c.malformedPackets = malformedPackets;
        c.sendDroppedVideoP = sendDroppedVideoP;
        c.sendDroppedAudio = sendDroppedAudio;
        c.sendQueueDepth = sendQueueDepth;
        c.recvVideoPackets = recvVideoPackets;
        c.recvAudioPackets = recvAudioPackets;
        c.recvVideoSkippedAwaitingKey = recvVideoSkippedAwaitingKey;
        c.recvVideoDecodeErrors = recvVideoDecodeErrors;
        c.recvAudioDecodeErrors = recvAudioDecodeErrors;
        c.recvAudioQueueDrops = recvAudioQueueDrops;
        c.recvDamagedVideoFrames = recvDamagedVideoFrames;
        c.protectionMode = protectionMode;
        c.fecPacketsEncoded = fecPacketsEncoded;
        c.fecPacketsDecoded = fecPacketsDecoded;
        c.fecDecodeFailures = fecDecodeFailures;
        c.nackRequestsSent = nackRequestsSent;
        c.nackRequestsReceived = nackRequestsReceived;
        c.nackRetransmits = nackRetransmits;
        c.nackCacheMisses = nackCacheMisses;
        c.unsupportedProtectionDropped = unsupportedProtectionDropped;
        c.fecPacketsStub = fecPacketsStub;
        c.nackRequestsStub = nackRequestsStub;
        c.nackRetransmitsStub = nackRetransmitsStub;
        return c;
    }

    /** Sync legacy fields for network stats wire format. */
    public synchronized void publishLegacyCounters() {
        fecPacketsStub = fecPacketsEncoded;
        nackRequestsStub = nackRequestsSent + nackRequestsReceived;
        nackRetransmitsStub = nackRetransmits;
    }

    /** Estimated UDP loss: incomplete reassembly + invalid, not double-counting fragments. */
    public synchronized long estimatedUdpLossEvents() {
        return reassemblyIncomplete + reassemblySuperseded + datagramsInvalid + malformedPackets;
    }
}
