import { AgoraRTCPlayer, VideoPlayer, LocalTrack, LocalDataChannel, RemoteDataChannel, LocalVideoTrackStats, AgoraRTCStats } from '@agora-js/media';
import { TurnServerConfigWithMode, CloudProxyServerMode, SDKStore, SDK_CODEC, SDK_AUDIO_CODEC, AgoraPCStats, UID, Candidate, Setup, EventEmitter, CandidateStats, FingerPrint, PromiseMutex } from '@agora-js/shared';
import { RTPCapabilitiesBeforeMerge, RTPCapabilitiesWithDirection } from '@agora-js/protocol';

interface PeerConnectionSpec {
    iceServers?: RTCIceServer[];
    turnServer?: TurnServerConfigWithMode;
    enableEncodedTransform?: boolean;
    isPreallocation?: boolean;
    cloudProxyServer?: CloudProxyServerMode;
}

interface RemoteConfig {
    tcc?: boolean;
    remb?: boolean;
    twcc?: boolean;
}

type Transmission = WebSocket | RTCDataChannel;

interface TransmissonInfo {
    transmitter: Transmission;
    close: () => void;
}

declare abstract class P2PConnectionBaseImpl extends EventEmitter {
    onICEConnectionStateChange?: (ICEConnectionState: RTCIceConnectionState) => void;
    onConnectionStateChange?: (connectionState: RTCPeerConnectionState) => void;
    onDTLSTransportStateChange?: (state: RTCDtlsTransportState) => void;
    onDTLSTransportError?: (error: any) => void;
    onICETransportStateChange?: (state: RTCIceTransportState) => void;
    onFirstAudioReceived?: (ssrcId: number) => void;
    onFirstVideoReceived?: (ssrcId: number) => void;
    onFirstAudioDecoded?: (ssrcId: number) => void;
    onFirstVideoDecoded?: (ssrcId: number, width: number, height: number) => void;
    onFirstVideoRender?: (ssrcId: number) => void;
    onFirstVideoBufferReady?: (ssrcId: number) => void;
    onFirstVideoDecodedTimeout?: (ssrcId: number) => void;
    onSelectedLocalCandidateChanged?: (cur: CandidateStats, prev: CandidateStats) => void;
    onSelectedRemoteCandidateChanged?: (cur: CandidateStats, prev: CandidateStats) => void;
    onICECandidateError?: (errMsg: string) => void;
    getLocalVideoStats?: () => LocalVideoTrackStats & AgoraRTCStats;
    constructor(spec: PeerConnectionSpec, store: SDKStore);
    abstract get currentLocalDescription(): RTCSessionDescription | null;
    abstract get currentRemoteDescription(): RTCSessionDescription | null;
    abstract get peerConnectionState(): RTCPeerConnectionState;
    abstract get iceConnectionState(): RTCIceConnectionState;
    abstract get localCodecs(): SDK_CODEC[];
}
declare abstract class P2PConnectionImpl extends P2PConnectionBaseImpl {
    abstract establishPromise: Promise<EstablishParams>;
    constructor(spec: PeerConnectionSpec, store: SDKStore);
    abstract establish(): Promise<EstablishParams>;
    abstract connect(connectParams: ConnectionParams): Promise<void | TransmissonInfo>;
    abstract updateRemoteConnect(connectParams: ConnectionParams): Promise<void>;
    abstract updateRemoteRTPCapabilities(mids: string[], codecs: SDK_CODEC[]): Promise<void>;
    abstract getPreMedia(ssrcId: number): {
        mid: string;
        track: MediaStreamTrack;
        transceiver: RTCRtpTransceiver;
        player: AgoraRTCPlayer | VideoPlayer | undefined;
    } | undefined;
    abstract send(tracks: LocalTrack[], codec: SDK_CODEC, audioCodec: SDK_AUDIO_CODEC): AsyncGenerator<SSRCMessage[], {
        localSSRC: SSRCMessage;
        id: string;
    }[], (RemoteConfig | undefined)[]>;
    abstract stopSending(mids: string[]): Promise<void>;
    abstract receive(kind: Kind, ssrcMsg: SSRCMessage, mslabel: string, remoteConfig: RemoteConfig | undefined): Promise<{
        track: MediaStreamTrack;
        id: string;
        transceiver?: RTCRtpTransceiver;
    }>;
    abstract batchReceive(list: {
        kind: Kind;
        ssrcMsg: SSRCMessage;
        mslabel: string;
    }[]): Promise<{
        track: MediaStreamTrack;
        id: string;
        transceiver?: RTCRtpTransceiver;
    }[]>;
    abstract stopReceiving(mids: string[]): Promise<void>;
    abstract muteRemote(mid: string): Promise<void>;
    abstract unmuteRemote(mid: string): Promise<void>;
    abstract muteLocal(mids: string[]): Promise<void>;
    abstract unmuteLocal(ids: string[]): Promise<void>;
    abstract restartICE(type?: ICERestartType): AsyncGenerator<ICEParameters, void, {
        remoteIceParameters: ICEParameters;
    }>;
    abstract close(): void;
    abstract getStats(): AgoraPCStats;
    abstract getRemoteVideoIsReady(ssrcId: number): boolean;
    abstract updateEncoderConfig(mid: string, track: LocalTrack): Promise<void>;
    abstract updateSendParameters(mid: string, track: LocalTrack): Promise<void>;
    abstract setStatsRemoteVideoIsReady(ssrcId: number, isReady: boolean): void;
    abstract replaceTrack(track: LocalTrack, id: string): Promise<void>;
    abstract getRemoteSSRC(mid: string): Promise<number | undefined>;
    abstract createDataChannels(uid: UID, dataChannels: LocalDataChannel[] | RemoteDataChannel[]): Promise<void>;
    abstract stopDataChannels(uid: UID): Promise<void>;
    abstract setConfiguration(spec: PeerConnectionSpec): void;
}
interface ICEParameters {
    iceUfrag: string;
    icePwd: string;
}
interface DtlsParameters {
    fingerprints: FingerPrint[];
}
declare enum Kind {
    VIDEO = "video",
    AUDIO = "audio"
}
declare enum ICERestartType {
    UDP_RELAY = "udp_relay",
    UDP_TCP_RELAY = "udp_tcp_relay",
    TCP_RELAY = "tcp_relay",
    RELAY = "relay"
}
type EstablishParams = {
    iceParameters: ICEParameters;
    dtlsParameters: DtlsParameters;
    rtpCapabilities: RTPCapabilitiesBeforeMerge;
    offerSDP?: string;
};
type ConnectionParams = {
    iceParameters: ICEParameters;
    dtlsParameters: DtlsParameters;
    candidates: Candidate[];
    rtpCapabilities: RTPCapabilitiesWithDirection;
    setup: Setup;
    cname: string;
    preallocation?: boolean;
    preSSRCs?: PreSSRCMessage[];
};
type SSRCMessage = {
    ssrcId: number;
    rtx?: number;
}[];
type PreSSRCMessage = {
    kind: Kind;
    ssrcMsg: SSRCMessage;
    mslabel: string;
};

type TRteServiceName = "ChannelMediaRelay" | "LiveStreaming" | "ImageModeration" | "ContentInspect" | "DataStream" | "P2PChannel" | "PlanBConnection" | "InterceptFrame" | "DataChannelConnection" | "DataChannelSignal";
interface IRteService<T = any, R = any> {
    name: TRteServiceName;
    create: (...args: any[]) => T;
    createSubmodule?: (...args: any[]) => R;
}

declare class PlanBConnection extends P2PConnectionImpl {
    private readonly store;
    private readonly peerConnection;
    private remoteSDP?;
    private initialOffer?;
    private statsFilter;
    private useRTX;
    private localCapabilities?;
    private localCandidateCount;
    private allCandidatesReceived;
    readonly establishPromise: Promise<EstablishParams>;
    protected mutex: PromiseMutex;
    get peerConnectionState(): RTCPeerConnectionState;
    get iceConnectionState(): RTCIceConnectionState;
    get currentLocalDescription(): RTCSessionDescription | null;
    get currentRemoteDescription(): RTCSessionDescription | null;
    get localCodecs(): SDK_CODEC[];
    constructor(spec: PeerConnectionSpec, store: SDKStore);
    establish(): Promise<EstablishParams>;
    updateRemoteConnect(): Promise<void>;
    connect(connectParams: ConnectionParams): Promise<void>;
    updateRemoteRTPCapabilities(mids: string[], codecs: SDK_CODEC[]): Promise<void>;
    getPreMedia(ssrcId: number): undefined;
    send(tracks: LocalTrack[], codec: SDK_CODEC): AsyncGenerator<SSRCMessage[], {
        localSSRC: SSRCMessage;
        id: string;
    }[], (RemoteConfig | undefined)[]>;
    stopSending(ids: string[]): Promise<void>;
    receive(kind: Kind, ssrcMsg: SSRCMessage, mslabel: string, remoteConfig?: RemoteConfig): Promise<{
        track: MediaStreamTrack;
        id: string;
        transceiver?: undefined;
    }>;
    stopReceiving(ids: string[]): Promise<void>;
    muteRemote(mid: string): Promise<void>;
    unmuteRemote(mid: string): Promise<void>;
    muteLocal(ids: string[]): Promise<void>;
    unmuteLocal(ids: string[]): Promise<void>;
    restartICE(type?: ICERestartType): AsyncGenerator<ICEParameters, void, {
        remoteIceParameters: ICEParameters;
    }>;
    close(): void;
    getStats(): AgoraPCStats;
    getRemoteVideoIsReady(ssrcId: number): boolean;
    updateEncoderConfig(mid: string, track: LocalTrack): Promise<void>;
    updateSendParameters(id: string, track: LocalTrack): Promise<void>;
    setStatsRemoteVideoIsReady(ssrcId: number, isReady: boolean): void;
    replaceTrack(track: LocalTrack, id: string): Promise<void>;
    createDataChannels(uid: UID, dataChannels: LocalDataChannel[] | RemoteDataChannel[]): Promise<void>;
    stopDataChannels(uid: UID): Promise<void>;
    private bindPCEvents;
    private unbindPCEvents;
    private static resolvePCConfiguration;
    private static turnServerConfigToIceServers;
    updateRtpSenderEncodings(track: LocalTrack, rtpSender?: RTCRtpSender): Promise<void>;
    private applySendEncodings;
    private mungSendOfferSDP;
    private bindStatsEvents;
    private unbindStatsEvents;
    batchReceive(receiveList: {
        kind: Kind;
        ssrcMsg: SSRCMessage;
        mslabel: string;
    }[]): Promise<{
        track: MediaStreamTrack;
        id: string;
    }[]>;
    getRemoteSSRC(id: string): Promise<number | undefined>;
    setConfiguration(spec: PeerConnectionSpec): void;
}
interface IPlanBConnectionOptions {
    spec: PeerConnectionSpec;
    store: SDKStore;
}
declare const PlanBConnectionService: IRteService<PlanBConnection>;

export { PlanBConnection, PlanBConnectionService };
export type { IPlanBConnectionOptions };
