package com.foxx.androidcast.network;

/*********************************************************************
 * CastTransportFactory.java
 * Created at: Fri 15 May 2026 16:49:02 +0200
 * Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
 * Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
 * class CastTransportFactory
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (6 commits, 90 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	87367475c8479ef541f606f782c652a202bedddca55a3275516a147205542471
**********************************************************************/
import android.content.Context;

import com.foxx.androidcast.CastConfig;
import com.foxx.androidcast.CastSettings;
import com.foxx.androidcast.network.quic.QuicCronetCastTransport;
import com.foxx.androidcast.network.usb.UsbTetherTransportFactory;
import com.foxx.androidcast.network.webrtc.WebRtcTransportFactory;

import java.io.IOException;

public final class CastTransportFactory {
    private static Context appContext;

    private CastTransportFactory() {}

    public static void init(Context context) {
        appContext = context.getApplicationContext();
    }

    public static CastTransport create(CastSettings settings) throws IOException {
        String mode = settings.getTransport();
        if (CastConfig.TRANSPORT_QUIC.equals(mode)) {
            if (appContext == null) {
                throw new IOException("CastTransportFactory.init(context) required for QUIC");
            }
            QuicCronetCastTransport quic = new QuicCronetCastTransport(appContext);
            applyUdpProtectionDeferred(quic.getUdpTransport());
            return quic;
        }
        if (WebRtcTransportFactory.isTransportId(mode)) {
            return WebRtcTransportFactory.create();
        }
        if (UsbTetherTransportFactory.isTransportId(mode)) {
            return UsbTetherTransportFactory.create();
        }
        if (CastConfig.TRANSPORT_UDP.equals(mode)) {
            UdpCastTransport udp = new UdpCastTransport();
            applyUdpProtectionDeferred(udp);
            return udp;
        }
        return new TcpCastTransport();
    }

    private static void applyUdpProtection(UdpCastTransport udp, CastSettings settings) {
        if (udp == null) {
            return;
        }
        udp.setProtectionEngine(com.foxx.androidcast.network.transport.StreamProtectionEngine.noop());
        if (settings == null || !CastConfig.TRANSPORT_UDP.equals(settings.getTransport())) {
            return;
        }
        udp.applyStreamProtection(settings);
    }

    /** UDP transports start with protection off until {@link #applyNegotiatedUdpProtection}. */
    public static void applyUdpProtectionDeferred(UdpCastTransport udp) {
        if (udp != null) {
            udp.setProtectionEngine(com.foxx.androidcast.network.transport.StreamProtectionEngine.noop());
        }
    }

    /**
     * Apply protection after handshake using negotiated local/remote preferences.
     *
     * @param localIsReceiver true when {@code local} is the receiver's capability from settings.
     * @return negotiation details (prompts, agreed mode) for UI/logging.
     */
    public static com.foxx.androidcast.network.transport.StreamProtectionNegotiation applyNegotiatedUdpProtection(
            UdpCastTransport udp, CastSettings local, CastSettings remote, boolean localIsReceiver) {
        if (udp == null || local == null) {
            return com.foxx.androidcast.network.transport.StreamProtectionNegotiation.none();
        }
        com.foxx.androidcast.network.transport.StreamProtectionNegotiation negotiated =
                com.foxx.androidcast.network.transport.StreamProtectionNegotiator.negotiate(
                        local.getStreamProtection(),
                        remote != null ? remote.getStreamProtection() : null,
                        localIsReceiver);
        CastSettings effective = new CastSettings();
        effective.copyFrom(local);
        effective.setStreamProtection(negotiated.agreed);
        udp.setProtectionEngine(com.foxx.androidcast.network.transport.StreamProtectionFactory.create(
                negotiated.agreed, udp.getLossStats(), negotiated.nackEnabled));
        return negotiated;
    }
}
