import { RTMConfiguration, TurnServerConfigWithMode, CloudProxyServerMode, EncryptionMode, EventEmitter, RetryConfiguration } from '@agora-js/shared';
import { RemoteStreamType, Resolution } from '@agora-js/media';

interface ServerAddress {
    ip: string;
    port: number;
    fingerprint?: string;
    domain_prefix?: string;
    ticket: string;
}
interface ChooseServerResponse {
    code: number;
    addresses: ServerAddress[];
    server_ts: number;
    uid: number;
    cid: number;
    cert: string;
    detail?: {
        [id: number]: string;
        candidate?: string;
    };
    cname?: string;
    flag?: number;
    opid?: number;
}
interface GatewayAddress {
    ip?: string;
    ip6?: string;
    port?: number;
    address: string;
}
interface MultiIpOptions {
    gateway_ip: string;
    uni_lbs_ip: string;
}

/**
 * Channel information in the media relay, used in [ChannelMediaRelayConfiguration]{@link IChannelMediaRelayConfiguration}.
 */
interface ChannelMediaRelayInfo {
    /**
     * The channel name.
     */
    channelName: string;
    /**
     * The token generated with the `channelName` and `uid`. Do not set this parameter if you have not enabled token.
     * The token for authentication. Do not set this parameter if you have not enabled token authentication.
     *
     * - When you set the information of the source channel, the token is generated with 0 and the source channel name.
     * - When you set the information of the destination channel, the token is generated with `uid` and the destination channel name.
     */
    token?: string;
    /**
     * The unique ID to identify the relay stream.
     *
     * A 32-bit unsigned integer with a value ranging from 0 to (2<sup>32</sup>-1). If you set it as `0`, the server assigns a random one.
     *
     * When used for the source channel, it is the ID to identify the relay stream in the source channel.
     *
     * When used for the destination channel, it is the ID to identify the relay stream in the destination channel. To avoid UID conflicts, this value must be different from any other user IDs in the destination channel.
     * - When you set the information of the source channel, set `uid` as the ID of the host whose stream is relayed.
     * - When you set the information of the destination channel, you can set `uid` as `0` (the server assigns a random one) or a 32-bit unsigned integer with a value ranging from 0 to (2<sup>32</sup>-1). To avoid UID conflicts, this value must be different from any other user IDs in the destination channel.
     */
    uid: number;
}

interface JoinInfo extends Partial<RTMConfiguration> {
    clientId: string;
    appId: string;
    sid: string;
    cname: string;
    turnServer: TurnServerConfigWithMode;
    proxyServer?: string;
    token: string;
    cloudProxyServer: CloudProxyServerMode;
    uid?: number | null;
    stringUid?: string;
    aespassword?: string;
    aessalt?: string;
    aesmode?: EncryptionMode;
    multiIP?: MultiIpOptions;
    optionalInfo?: string;
    appScenario?: string;
    useLocalAccessPoint: boolean;
    apUrl?: string;
    defaultVideoStream?: RemoteStreamType;
    license?: string;
    setLocalAPVersion?: number;
    preload?: boolean;
    apRequestDetail?: string;
    role?: "host" | "audience";
}
interface JoinInfoWithAPResponse extends JoinInfo {
    cid: number;
    uid: number;
    vid?: string;
    apResponse: ChooseServerResponse;
    apGatewayAddress?: GatewayAddress;
    gatewayAddrs: GatewayAddress[];
    uni_lbs_ip?: string;
}

/**
 * Configurations of the media stream relay.
 *
 * Use this interface to set the media stream relay when calling [startChannelMediaRelay]{@link IAgoraRTCClient.startChannelMediaRelay} or [updateChannelMediaRelay]{@link IAgoraRTCClient.updateChannelMediaRelay}.
 *
 * ```javascript
 * const configuration = AgoraRTC.createChannelMediaRelayConfiguration();
 * configuration.setSrcChannelInfo({ channelName: "test", token: "xxx", uid: 12345 });
 * configuration.addDestChannelInfo({ channelName: "test2", token: "xxx", uid: 23456 });
 * ```
 */
interface IChannelMediaRelayConfiguration {
    /**
     * Sets the information of the source channel.
     *
     * ```javascript
     * const config = AgoraRTC.createChannelMediaRelayConfiguration();
     * config.setSrcChannelInfo({ channelName: "test", token: "xxx", uid: 123456 });
     * ```
     * @param info The information of the source channel.
     */
    setSrcChannelInfo(info: ChannelMediaRelayInfo): void;
    /**
     * Adds a destination channel.
     *
     * To relay a media stream across multiple channels, call this method as many times (to a maximum of four).
     *
     * ```javascript
     * const config = AgoraRTC.createChannelMediaRelayConfiguration();
     * config.addDestChannelInfo({ channelName: "test2", token: "xxx", uid: 23456 });
     * config.addDestChannelInfo({ channelName: "test3", token: "xxx", uid: 23457 });
     * ```
     *
     * @param info The information of the destination channel.
     */
    addDestChannelInfo(info: ChannelMediaRelayInfo): void;
    /**
     * Removes the destination channel added through {@link addDestChannelInfo}.
     * @param channelName The name of the destination channel to be removed.
     */
    removeDestChannelInfo(channelName: string): void;
}

declare class ChannelMediaRelayConfiguration implements IChannelMediaRelayConfiguration {
    private destChannelMediaInfos;
    private srcChannelMediaInfo?;
    setSrcChannelInfo(info: ChannelMediaRelayInfo): void;
    addDestChannelInfo(info: ChannelMediaRelayInfo): void;
    removeDestChannelInfo(channelName: string): void;
}

declare class AgoraChannelMediaRelayClient extends EventEmitter {
    private joinInfo;
    private sid;
    private clientId;
    private cancelToken;
    private workerToken?;
    private requestId;
    private signal;
    private prevChannelMediaConfig?;
    private httpRetryConfig;
    private _resolution;
    private set state(value);
    private get state();
    private _state;
    private errorCode;
    constructor(joinInfo: JoinInfoWithAPResponse, clientId: string, wsRetryConfig: RetryConfiguration, httpRetryConfig: RetryConfiguration, resolution: Resolution);
    startChannelMediaRelay(configuration: ChannelMediaRelayConfiguration): Promise<void>;
    updateChannelMediaRelay(configuration: ChannelMediaRelayConfiguration): Promise<void>;
    setVideoProfile(resolution: Resolution): Promise<void>;
    stopChannelMediaRelay(): Promise<void>;
    dispose(): void;
    private connect;
    private sendStartRelayMessage;
    private sendUpdateMessage;
    private sendStopRelayMessage;
    private genMessage;
    private onStatus;
    private onReconnect;
}

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

interface IChannelMediaRelayOptions {
    joinInfo: JoinInfoWithAPResponse;
    clientId: string;
    websocketRetryConfig?: RetryConfiguration;
    httpRetryConfig?: RetryConfiguration;
    resolution: Resolution;
}
declare const ChannelMediaRelayService: IRteService<AgoraChannelMediaRelayClient>;

export { AgoraChannelMediaRelayClient, ChannelMediaRelayService, type IChannelMediaRelayOptions };
