export class VideoSDK {
  static Constants: {
    errors: typeof Errors;
    recordingEvents: typeof recordingEvents;
    livestreamEvents: typeof livestreamEvents;
    hlsEvents: typeof hlsEvents;
    transcriptionEvents: typeof transcriptionEvents;
    modes: typeof modes;
    permission: typeof Permission;
    reliabilityMode: typeof reliabilityMode;
    leaveReason: typeof leaveReason;
    BitrateMode: typeof BitrateMode;
    LogLevel: typeof LogLevel;
  };

  /**
   * - This method can be used to configure the VideoSDK with an authentication token.
   * - Before initializing a meeting, you must provide a valid token using this method.
   *
   * @param token
   * - Authentication token used to authorize SDK operations.
   *
   * You can generate a token in the following ways:
   *
   * 1. **Temporary Token** – Generate it from the
   *    [Dashboard API Keys](https://app.videosdk.live/api-keys).
   * 2. **Server-generated Token** – Generate a JWT on your backend and fetch it securely.
   *
   * @example
   * ```ts
   * const token = "<YOUR_TOKEN_FROM_DASHBOARD>";
   * VideoSDK.config(token);
   * ```
   */
  static config(token: string): void;

  /**
   * - This method can be used to initialize a meeting and return a `Meeting` instance.
   *
   * @param options Configuration options for initializing the meeting.
   *
   * @returns
   *
   * @example
   * ```js
   * const meeting = VideoSDK.initMeeting({
   *    meetingId: "abc-1234-xyz",
   *    name: "John Doe",
   *    micEnabled: true,
   *    webcamEnabled: true,
   *    maxResolution: "hd",
   *    multiStream: true,
   *    mode: "SEND_AND_RECV",
   * });
   * ```
   */
  static initMeeting(options: {
    /**
     * Unique ID of the meeting to join. Please refer this [documentation](https://docs.videosdk.live/api-reference/realtime-communication/create-room) to create a room.
     */
    meetingId: string;

    /**
     * Custom camera video track to use as the camera input.
     *
     * If this is not provided, the SDK will automatically create and use a default camera video track. You can create a custom track using {@link createCameraVideoTrack}.
     */
    customCameraVideoTrack?: MediaStream;

    /**
     * Custom microphone audio track to use as the microphone input.
     *
     * If this is not provided, the SDK will automatically create and use a default microphone audio track.You can create a custom track using {@link createMicrophoneAudioTrack}.
     */
    customMicrophoneAudioTrack?: MediaStream;

    /**
     * Preferred network protocol for media transmission.
     *
     * **Allowed Value:**
     *
     * - **UDP_OVER_TCP (default)**: Initially the server attempts to establish a connection using UDP, if that fails it automatically switches to TCP protocol.
     * - **UDP_ONLY**: Force UDP protocol
     * - **TCP_ONLY**: Force TCP protocol
     */
    preferredProtocol?: "UDP_ONLY" | "UDP_OVER_TCP" | "TCP_ONLY";

    /**
     * Defines how media streams should behave.There are 3 types of {@link modes}
     */
    mode?: "SEND_AND_RECV" | "SIGNALLING_ONLY" | "RECV_ONLY";

    /**
     * Enables or disables multi-resolution streaming.
     *
     * @default true
     */
    multiStream?: boolean;

    /**
     * Unique participant identifier.
     */
    participantId?: string;

    /**
     * Display name of the participant.
     */
    name?: string;

    /**
     * Enables microphone on join.
     *
     * @default false
     */
    micEnabled?: boolean;

    /**
     * Enables webcam on join.
     *
     * @default false
     */
    webcamEnabled?: boolean;

    /**
     * Maximum resolution for video publishing.
     *
     * @default "hd"
     */
    maxResolution?: "hd" | "sd";

    /**
     * Custom metadata associated with the participant.
     */
    metaData?: object;

    /**
     * Enables detailed SDK logs in the dashboard.
     *
     * @default true
     */
    debugMode?: boolean;

    /**
     * If you want to use a proxy server with the VideoSDK, you can specify your baseURL here.
     *
     * > **Note**
     * >
     * > If you intend to use a proxy server with the VideoSDK, priorly inform us at support@videosdk.live
     */
    signalingBaseUrl?: string;

    /**
     * Specifies which camera to use by default.
     *
     * - `user` → front camera
     * - `environment` → rear camera
     */
    defaultCamera?: "user" | "enviornment";
  }): Meeting;

  /**
   * - This method can be used to create video track using different encoding parameters, camera facing mode, bitrateMode, maxLayer and optimization mode.
   *
   * @example
   * ```ts
   * const customTrack = await VideoSDK.createCameraVideoTrack({
   *   optimizationMode: "motion",
   *   encoderConfig: "h540p_w960p",
   *   facingMode: "environment",
   *   bitrateMode: VideoSDK.Constants.BitrateMode.HIGH_QUALITY,
   *   maxLayer: 2,
   *   multiStream: true,
   * });
   * ```
   * @returns
   */
  static createCameraVideoTrack(options?: {
    /**
     * It will be the id of the camera from which the video should be captured.
     */
    cameraId?: string;

    /**
     *  You can choose from the below mentioned list of values for the encoder config.
     *
     * Supported values include:
     * | Encoder Config | Resolution | Frame Rate | Optimized (kbps) | Balanced (kbps) | High Quality (kbps) |
     * | -------------- | :--------: | :--------: | :----------: | :----------: | :----------: |
     * | h90p_w160p | 160x90 | 15 fps | 60  | 100 | 150|
     * | h180p_w320p | 320x180 | 15 fps | 100 | 150 | 250 |
     * | h216p_w384p | 384x216 | 15 fps | 120 | 200 | 350 |
     * | h360p_w640p | 640x360 | 20 fps | 200 | 400 | 600 |
     * | h540p_w960p | 960x540 | 25 fps | 350 | 550 | 800 |
     * | h720p_w1280p | 1280x720 | 30 fps | 1000 | 1500 | 2000 |
     * | h1080p_w1920p | 1920x1080 | 30 fps | 1600 | 2200 | 2700 |
     * | h1440p_w2560p | 2560x1440 | 30 fps | 5000 | 5500 | 6000 |
     * | h2160p_w3840p | 3840x2160 | 30 fps | 8000 | 8500 | 9000 |
     * | h120p_w160p | 160x120 | 15 fps | 60 | 100 | 150 |
     * | h180p_w240p | 240x180 | 15 fps | 100 | 150 | 250 |
     * | h240p_w320p | 320x240 | 15 fps | 120 | 200 | 350 |
     * | h360p_w480p | 480x360 | 20 fps | 200 | 400 | 600 |
     * | h480p_w640p | 640×480 | 25 fps | 300 | 500 | 700 |
     * | h540p_w720p | 720×540 | 30 fps | 350 | 550 | 800 |
     * | h720p_w960p | 960×720 | 30 fps | 900 | 1300 | 1600 |
     * | h1080p_w1440p | 1440×1080 | 30 fps | 1600 | 2200 | 2700 |
     * | h1440p_w1920p | 1920×1440 | 30 fps | 3500 | 4000 | 4500 |
     *
     * > **Note**
     * >
     * > Above mentioned encoder configurations are valid for both, landscape as well as portrait mode.
     *
     * @default "h720p_w1280p"
     *
     */
    encoderConfig?:
      | "h90p_w160p"
      | "h180p_w320p"
      | "h216p_w384p"
      | "h360p_w640p"
      | "h540p_w960p"
      | "h720p_w1280p"
      | "h1080p_w1920p"
      | "h1440p_w2560p"
      | "h2160p_w3840p"
      | "h120p_w160p"
      | "h180p_w240p"
      | "h240p_w320p"
      | "h360p_w480p"
      | "h480p_w640p"
      | "h540p_w720p"
      | "h720p_w960p"
      | "h1080p_w1440p"
      | "h1440p_w1920p";

    /**
     * It will specify whether to use front or back camera for the video track.
     */
    facingMode?: "user" | "environment";

    /**
     * It will specify the optimization mode for the video track being generated.
     */
    optimizationMode?: "text" | "motion" | "detail";

    /**
     * It will specify if the stream should send multiple resolution layers or single resolution layer.
     *
     * > **Info**
     * >
     * > For meetings with fewer than or equal to four participants, setting `multiStream:false` is regarded as best practice.
     *
     * @default true
     */
    multiStream?: boolean;

    /**
     * Controls the video quality and bandwidth consumption. You can choose between `high_quality` for the best picture, `bandwidth_optimized` to save data, or `balanced` for a mix of both. Defaults to `balanced`.
     *
     * **Allowed Value:** {@link BitrateMode}
     *
     * @default BitrateMode.BALANCED
     */
    bitrateMode?: "high_quality" | "balanced" | "bandwidth_optimized";

    /**
     * Specifies the maximum number of simulcast layers to publish. This parameter only has an effect if `multiStream` is set to true.
     */
    maxLayer?: 2 | 3;
  }): Promise<MediaStream>;

  /**
   * - This method can be used to create screen share track using different encoding parameters and optimization mode.
   *
   * @example
   * ```js
   * import VideoSDK from "@videosdk.live/js-sdk";
   *
   *  let customTrack = await VideoSDK.createScreenShareVideoTrack({
   *    optimizationMode: "motion",
   *    encoderConfig: "h720p_15fps",
   *    withAudio:'enable'
   *    multiStream: true
   *  });
   * ```
   * @returns
   */
  static createScreenShareVideoTrack(options?: {
    /**
     * You can choose from the below mentioned list of values for the encoder config.
     *
     * | Encoder Config | Resolution | Frame Rate | Bitrate   |
     * | -------------- | ---------- | ---------- | ----------|
     * | h360p_30fps    | 640x360    | 30 fps     | 400 kbps  |
     * | h480p_15fps    | 854x480    | 15 fps     | 300 kbps  |
     * | h480p_30fps    | 854x480    | 30 fps     | 500 kbps  |
     * | h720p_5fps     | 1280x720   | 5 fps      | 400 kbps  |
     * | h720p_15fps    | 1280x720   | 15 fps     | 1000 kbps |
     * | h720p_30fps    | 1280x720   | 30 fps     | 1500 kbps |
     * | h1080p_15fps   | 1920x1080  | 15 fps     | 1500 kbps |
     * | h1080p_30fps   | 1920x1080  | 30 fps     | 2000 kbps |
     *
     * > **Note**
     * >
     * > Above mentioned encoder configurations are valid for both, landscape as well as portrait mode.
     *
     * @default "h720p_15fps"
     */
    encoderConfig?:
      | "h360p_30fps"
      | "h480p_15fps"
      | "h480p_30fps"
      | "h720p_5fps"
      | "h720p_15fps"
      | "h720p_30fps"
      | "h1080p_15fps"
      | "h1080p_30fps";

    /**
     * Optimization strategy for screen sharing.
     */
    optimizationMode?: "text" | "motion" | "detail";

    /**
     * Enables or disables audio during screen sharing.
     *
     * @default "enable"
     */
    withAudio?: "enable" | "disable";

    /**
     * It will specify if the stream should send multiple resolution layers or single resolution layer.
     *
     * @default false
     */
    multiStream?: boolean;
  }): Promise<MediaStream>;

  /**
   * - This method can be used to create audio track using different encoding parameters and noise cancellation configuration.
   *
   * @param options
   * @param options.microphoneId
   * It will be the id of the mic from which the audio should be captured.
   *
   * @param options.encoderConfig
   * **Default:** `"speech_standard"`
   *
   * - It will be the encoder configuration you want to use for Audio Track.
   * - You can choose from the below mentioned list of values for the encoder config.
   *
   * | Encoder Config      | Bitrate  | Auto Gain | Echo Cancellation | Noise Suppression |
   * | ------------------- | :------: | :-------: | :---------------: | :---------------: |
   * | speech_low_quality  | 16 kbps  |   TRUE    |       TRUE        |       TRUE        |
   * | speech_standard     | 24 kbps  |   TRUE    |       TRUE        |       TRUE        |
   * | music_standard      | 32 kbps  |   FALSE   |       FALSE       |       FALSE       |
   * | standard_stereo     | 64 kbps  |   FALSE   |       FALSE       |       FALSE       |
   * | high_quality        | 128 kbps |   FALSE   |       FALSE       |       FALSE       |
   * | high_quality_stereo | 192 kbps |   FALSE   |       FALSE       |       FALSE       |
   *
   * @param options.noiseConfig
   * Configuration for audio noise processing.
   *
   * @param options.noiseConfig.echoCancellation
   * If `true` echo cancellation will turned on else it would be turned off.
   *
   * @param options.noiseConfig.autoGainControl
   * If `true` auto gain will turned on else it would be turned off.
   *
   * @param options.noiseConfig.noiseSuppression
   * If `true` noise suppression will turned on else it would be turned off.
   *
   *
   * @example
   * ```ts
   * const customTrack = await VideoSDK.createMicrophoneAudioTrack({
   *   encoderConfig: "high_quality",
   *   noiseConfig: {
   *     noiseSuppression: true,
   *     echoCancellation: true,
   *     autoGainControl: true,
   *   },
   * });
   * ```
   * @returns
   */
  static createMicrophoneAudioTrack(options?: {
    noiseConfig?: {
      echoCancellation: boolean;
      autoGainControl: boolean;
      noiseSuppression: boolean;
    };
    encoderConfig?:
      | "speech_low_quality"
      | "speech_standard"
      | "music_standard"
      | "standard_stereo"
      | "high_quality"
      | "high_quality_stereo";
    microphoneId?: string;
  }): Promise<MediaStream>;

  /**
   * - This method can be used to retrieve a list of currently available video input devices.
   * - The returned `Promise` resolves with an array of {@link CameraDeviceInfo} objects.
   */
  static getCameras(): Promise<Array<CameraDeviceInfo>>;

  /**
   * - This method can be used to retrieve a list of currently available audio input devices.
   * - The returned `Promise` resolves with an array of {@link MicrophoneDeviceInfo} objects.
   */
  static getMicrophones(): Promise<Array<MicrophoneDeviceInfo>>;

  /**
   * - This method can be used to retrieve a list of currently available playback devices.
   * - The returned `Promise` resolves with an array of {@link PlaybackDeviceInfo} objects.
   */
  static getPlaybackDevices(): Promise<Array<PlaybackDeviceInfo>>;

  /**
   * - This method can be used to retrieve a list of all currently available media input and output devices.
   * - The returned `Promise` resolves with an array of {@link DeviceInfo} objects.
   */
  static getDevices(): Promise<Array<DeviceInfo>>;


  /**
   * Registers an event listener.
   * @param eventType Event name to which you want to subscribe.
   * @param listener Callback function which will be triggered when the event happens
   *
   * To view the complete list of available events and their details, refer to {@link VideosdkEvent}
   */
  static on(eventType: "device-changed", listener: (data: any) => void): void;

  /**
   * Removes an event listener that was previously registered.
   * @param eventType Event name to which you want to unsubscribe.
   * @param listener Callback function which was passed while subscribing to the event
   *
   * To view the complete list of available events and their details, refer to {@link VideosdkEvent}
   */
  static off(eventType: "device-changed", listener: (data: any) => void): void;

  /**
   * - This method can be used to check whether the application already has permission to access media input devices.
   * - It returns a `Promise` that resolves to a `Map<string, boolean>` indicating the permission status.
   *
   * @param permissions
   * Specifies the type of media permission to request.
   *
   * **Allowed value:** {@link Permission}
   *
   * @default AUDIO_AND_VIDEO
   *
   * @returns
   * A Promise that resolves to a `Map<string, boolean>` where:
   * - `true` indicates permission is granted
   * - `false` indicates permission is denied
   *
   * @example
   * ```ts
   * try {
   *   const checkAudioVideoPermission = await VideoSDK.checkPermissions(
   *     VideoSDK.Constants.permission.AUDIO_AND_VIDEO
   *   );
   *
   *   console.log(
   *     "check Audio and Video Permissions",
   *     checkAudioVideoPermission.get(VideoSDK.Constants.permission.AUDIO),
   *     checkAudioVideoPermission.get(VideoSDK.Constants.permission.VIDEO)
   *   );
   * } catch (ex) {
   *   console.log("Error in checkPermissions", ex);
   * }
   * ```
   *
   * > **Note**
   * >
   * > This method will throw an error if the browser does not support permission checking functionality.
   */
  static checkPermissions(permissions?: string): Promise<Map<string, boolean>>;

  /**
   * - This method can be used to prompt the user for permission to access media input devices.
   * - It requests permission for the specified media types and returns the permission status for each requested media kind.
   *
   * @param permissions
   * Specifies the type of media permission to request.
   *
   * **Allowed value:** {@link Permission}
   *
   * @example
   * ```js
   * try {
   *   const requestPermission = await VideoSDK.requestPermission(
   *       VideoSDK.Constants.permission.AUDIO_AND_VIDEO,
   *   );
   *   console.log(
   *     "request Audio and Video Permissions",
   *     requestPermission.get(VideoSDK.Constants.permission.AUDIO),
   *     requestPermission.get(VideoSDK.Constants.permission.VIDEO)
   *   );
   * } catch(ex)
   * {
   *   console.log("Error in requestPermission ", ex);
   * }
   * ```
   *
   * > **Note**
   * >
   * > `requestPermission()` will throw an error when matching media is not available.
   *
   */
  static requestPermission(permissions?: string): Promise<Map<string, boolean>>;

  /**
   * - This method can be used to set the End-to-End Encryption (E2EE) key provider.
   * - The key provider must be an instance of {@link ExternalE2EEKeyProvider} that contains a shared encryption key.
   * - Before passing the provider to this method, ensure that the shared key is set using `keyProvider.setSharedKey(...)`.
   * - If the key provider is set before initializing a meeting, E2EE will be enabled automatically.
   *
   * @example
   * ```ts
   * import { ExternalE2EEKeyProvider } from "@videosdk.live/js-sdk";
   *
   * const keyProvider = new ExternalE2EEKeyProvider();
   * keyProvider.setSharedKey("<SECRET_KEY>");
   *
   * // Set the key provider before initializing the meeting.
   * // If the key is set before initialization, E2EE is enabled automatically.
   * VideoSDK.setKeyProvider(keyProvider);
   *
   * const meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   * ```
   */
  static setKeyProvider(keyProvider: ExternalE2EEKeyProvider): void;

  /**
   * Updates the SDK logging verbosity level.
   *
   * Higher verbosity levels show more detailed logs, including messages from lower levels, helping with debugging while keeping console output manageable.
   *
   * The log level can be modified at runtime and is applied immediately.
   *
   * @example
   * ```js
   * VideoSDK.setLogLevel(VideoSDK.Constants.LogLevel.ALL);
   * ```
   */
  static setLogLevel(
    /**
     * Defines how media streams should behave {@link LogLevel}.
     *
     * @default LogLevel.INFO
     */
    logLevel?: "NONE" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "ALL",
  ): void;

  /**
   * - Runs a pre-call test to evaluate the user's network quality and media devices before joining a meeting.
   * - Returns a `Promise` that resolves with the test results or rejects with a {@link PreCallTestError} if the test fails.
   * - The `options` parameter can be used to configure the test duration, provide custom media tracks, and receive live stats updates via the `onStatsChange` callback.
   * - The returned `Promise` also includes a `.stop()` method, which allows the test to be cancelled before completion.
   *
   * @example
   * ```ts
   * VideoSDK.runPreCallTest({
   *  token: TOKEN,
   *  samplingDuration: 120000,
   *  audioOnly: true,
   *  videoTrack: customVideoTrack,
   *  audioTrack: customAudioTrack,
   *  onStatsChange: (stats) => {
   *   console.log("stats", stats);
   *  },
   * })
   * .then((result) => {
   *   console.log("Pre-call test result:", result);
   * })
   * .catch((err) => {
   *   console.log("code : " + err.code);
   *   console.log("message : " + err.message);
   * });
   * ```
   *
   * @param options
   */
  static runPreCallTest(options: {
    /**
     * Authentication token used to authorize SDK operations. You can generate a token in the following ways:
     *
     * 1. **Temporary Token** – Generate it from the [Dashboard API Keys](https://app.videosdk.live/api-keys).
     * 2. **Server-generated Token** – Generate a JWT on your backend and fetch it securely.
     */
    token: string;

    /** Duration for sampling stats during the test, in milliseconds.
     * Minimum: `10000`, Maximum: `120000`.
     *
     * @default 15000
     */
    samplingDuration?: number;

    /** Skips the camera test and runs the pre-call test using audio only.
     *
     * @default false
     */
    audioOnly?: boolean;

    /**
     * Your own camera track that is created by {@link createCameraVideoTrack}.
     */
    videoTrack?: MediaStream;

    /**
     * Your own microphone track that is created by {@link createMicrophoneAudioTrack}.
     */
    audioTrack?: MediaStream;

    videoConfig?: {
      /** It will be the id of the camera from which the video should be captured. */
      cameraId?: string;

      /**
       * You can choose from the below mentioned list of values for the encoder config.
       *
       * Supported values include:
       * | Encoder Config | Resolution | Frame Rate | Optimized (kbps) | Balanced (kbps) | High Quality (kbps) |
       * | -------------- | :--------: | :--------: | :----------: | :----------: | :----------: |
       * | h90p_w160p | 160x90 | 15 fps | 60  | 100 | 150|
       * | h180p_w320p | 320x180 | 15 fps | 100 | 150 | 250 |
       * | h216p_w384p | 384x216 | 15 fps | 120 | 200 | 350 |
       * | h360p_w640p | 640x360 | 20 fps | 200 | 400 | 600 |
       * | h540p_w960p | 960x540 | 25 fps | 350 | 550 | 800 |
       * | h720p_w1280p | 1280x720 | 30 fps | 1000 | 1500 | 2000 |
       * | h1080p_w1920p | 1920x1080 | 30 fps | 1600 | 2200 | 2700 |
       * | h1440p_w2560p | 2560x1440 | 30 fps | 5000 | 5500 | 6000 |
       * | h2160p_w3840p | 3840x2160 | 30 fps | 8000 | 8500 | 9000 |
       * | h120p_w160p | 160x120 | 15 fps | 60 | 100 | 150 |
       * | h180p_w240p | 240x180 | 15 fps | 100 | 150 | 250 |
       * | h240p_w320p | 320x240 | 15 fps | 120 | 200 | 350 |
       * | h360p_w480p | 480x360 | 20 fps | 200 | 400 | 600 |
       * | h480p_w640p | 640×480 | 25 fps | 300 | 500 | 700 |
       * | h540p_w720p | 720×540 | 30 fps | 350 | 550 | 800 |
       * | h720p_w960p | 960×720 | 30 fps | 900 | 1300 | 1600 |
       * | h1080p_w1440p | 1440×1080 | 30 fps | 1600 | 2200 | 2700 |
       * | h1440p_w1920p | 1920×1440 | 30 fps | 3500 | 4000 | 4500 |
       *
       * > **Note**
       * >
       * > Above mentioned encoder configurations are valid for both, landscape as well as portrait mode.
       *
       * @default "h720p_w1280p"
       */
      encoderConfig?:
        | "h90p_w160p"
        | "h180p_w320p"
        | "h216p_w384p"
        | "h360p_w640p"
        | "h540p_w960p"
        | "h720p_w1280p"
        | "h1080p_w1920p"
        | "h1440p_w2560p"
        | "h2160p_w3840p"
        | "h120p_w160p"
        | "h180p_w240p"
        | "h240p_w320p"
        | "h360p_w480p"
        | "h480p_w640p"
        | "h540p_w720p"
        | "h720p_w960p"
        | "h1080p_w1440p"
        | "h1440p_w1920p";

      /** Specifies whether to use the front or back camera for the video track. */
      facingMode?: "user" | "environment";

      /** It will specify the optimization mode for the video track being generated. */
      optimizationMode?: "text" | "motion" | "detail";

      /**
       * It will specify if the stream should send multiple resolution layers or single resolution layer.
       *
       * > **Info**
       * >
       * > For meetings with fewer than or equal to four participants, setting `multiStream:false` is regarded as best practice.
       *
       * @default true
       */
      multiStream?: boolean;

      /**
       * Controls the video quality and bandwidth consumption. You can choose between `high_quality` for the best picture, `bandwidth_optimized` to save data, or `balanced` for a mix of both. Defaults to `balanced`.
       *
       * **Allowed Value:** {@link BitrateMode}
       *
       * @default BitrateMode.BALANCED
       */
      bitrateMode?: "high_quality" | "balanced" | "bandwidth_optimized";

      /** Specifies the maximum number of simulcast layers to publish. Only effective when `multiStream` is true. */
      maxLayer?: 2 | 3;
    };

    audioConfig?: {
      /**
       * Configuration for audio noise processing.
       */
      noiseConfig?: {
        /**
         * If `true` echo cancellation will turned on else it would be turned off.
         */
        echoCancellation: boolean;
        /**
         * If `true` auto gain will turned on else it would be turned off.
         */
        autoGainControl: boolean;
        /**
         * If `true` noise suppression will turned on else it would be turned off.
         */
        noiseSuppression: boolean;
      };
      /**
       *
       * - It will be the encoder configuration you want to use for Audio Track.
       * - You can choose from the below mentioned list of values for the encoder config.
       *
       * | Encoder Config      | Bitrate  | Auto Gain | Echo Cancellation | Noise Suppression |
       * | ------------------- | :------: | :-------: | :---------------: | :---------------: |
       * | speech_low_quality  | 16 kbps  |   TRUE    |       TRUE        |       TRUE        |
       * | speech_standard     | 24 kbps  |   TRUE    |       TRUE        |       TRUE        |
       * | music_standard      | 32 kbps  |   FALSE   |       FALSE       |       FALSE       |
       * | standard_stereo     | 64 kbps  |   FALSE   |       FALSE       |       FALSE       |
       * | high_quality        | 128 kbps |   FALSE   |       FALSE       |       FALSE       |
       * | high_quality_stereo | 192 kbps |   FALSE   |       FALSE       |       FALSE       |
       *
       * @default "speech_standard"
       */
      encoderConfig?:
        | "speech_low_quality"
        | "speech_standard"
        | "music_standard"
        | "standard_stereo"
        | "high_quality"
        | "high_quality_stereo";

      /**
       * It will be the id of the mic from which the audio should be captured.
       */
      microphoneId?: string;
    };

    /** Receives the latest network stats while the test is running. */
    onStatsChange?: (stats: object) => void;
  }): Promise<{
    aborted: boolean;
    testDuration: number;
    camera: object;
    microphone: object;
    network: object;
  }> & {
    /**
     * Idempotent method to stop the ongoing pre-call test.
     * Cleans up all allocated resources and resolves once teardown is complete.
     */
    stop(): Promise<void>;
  };
}

/**
 * Error thrown via Promise rejection from {@link VideoSDK.runPreCallTest}, and surfaced inside the resolved result for any phase (camera, microphone, network) that fails.
 */
export class PreCallTestError {
  /**
   * Stable SDK error code.
   *
   * | Code | Description |
   * | ---- | ----------- |
   * | `ERROR_CAMERA_NOT_FOUND`| Please ensure your camera is connected and turned on, and that the camera driver is installed and up-to-date.|
   * | `ERROR_CAMERA_ACCESS_DENIED_OR_DISMISSED` | Oops! It seems like camera access was denied or dismissed. To proceed, kindly grant access through your browser settings. |
   * | `ERROR_CAMERA_IN_USE` | The camera is being used by another application. Please close any programs utilizing the camera, such as video conferencing tools, screen recording software, or other browsers. Restart your browser and attempt again. |
   * | `ERROR_CAMERA_CONSTRAINT_NOT_SATISFIED` | The camera cannot satisfy the requested constraints (resolution, frame rate, etc.). |
   * | `ERROR_WEBCAM_TRACK_ENDED` | Webcam track has ended or the webcam is disconnected. Please ensure your webcam is properly connected and try restarting it. |
   * | `ERROR_VIDEO_SOURCE_INITIATION_FAILED` | Unable to initiate video source. Please verify browser settings for video permissions. |
   * | `ERROR_INVALID_CUSTOM_VIDEO_TRACK` | The provided videoTrack is invalid. Pass a MediaStream containing a live video track. |
   * | `ERROR_MICROPHONE_NOT_FOUND` | Please ensure your microphone is connected and turned on. |
   * | `ERROR_MICROPHONE_ACCESS_DENIED_OR_DISMISSED` | Oops! It seems like microphone access was denied or dismissed. To proceed, kindly grant access through your browser settings. |
   * | `ERROR_MICROPHONE_IN_USE` | The microphone is being used by another application. Please close any programs utilizing the microphone, such as video conferencing tools, screen recording software, or other browsers. Restart your browser and attempt again. |
   * | `ERROR_MICROPHONE_CONSTRAINT_NOT_SATISFIED` | The microphone cannot satisfy the requested constraints (sample rate, channels, etc.). |
   * | `ERROR_MICROPHONE_TRACK_ENDED` | Microphone track has ended or the microphone is disconnected. Please check your microphone connection and try again. |
   * | `ERROR_AUDIO_SOURCE_INITIATION_FAILED` | Unable to initiate audio source. |
   * | `ERROR_INVALID_CUSTOM_AUDIO_TRACK` | The provided audioTrack is invalid. Pass a MediaStream containing a live audio track. |
   * | `ERROR_PRECALL_TEST_ALREADY_RUNNING` | A pre-call test is already running. Stop the active test before starting a new one. |
   * | `ERROR_PRECALL_INVALID_CONFIG` | Invalid configuration passed to `runPreCallTest`. |
   * | `ERROR_PRECALL_INVALID_TOKEN` | Authentication token is missing, empty, or invalid. |
   * | `ERROR_PRECALL_MEDIA_CHECK_FAILED` | Pre-call test cannot continue — neither camera nor microphone could be acquired. |
   * | `ERROR_PRECALL_TEST_FAILED` | The pre-call network test could not be completed. Please try again. |
   */
  code: string;

  /** Message paired with `code` — matches the description column above. */
  message: string;
}

export type VideosdkEvent = {
  /**
   * @event
   *
   * - Triggered whenever a media device (camera, microphone, or speaker) is connected to or disconnected from the system.
   *
   * - This event emits the **updated list of available devices** after the change has occurred.
   *
   * @param devices
   * An array of currently available media devices.
   *
   * @example
   * ```ts
   * import VideoSDK from "@videosdk.live/js-sdk";
   *
   * VideoSDK.on("device-changed", (devices) => {
   *   // devices: DeviceInfo[]
   *   console.log(devices);
   * });
   * ```
   */
  "device-changed": (devices: DeviceInfo[]) => void;
};

import {
  CameraDeviceInfo,
  DeviceInfo,
  MicrophoneDeviceInfo,
  PlaybackDeviceInfo,
} from "./classes/DeviceInfo";
import {
  ExternalE2EEKeyProvider,
  E2EEKeyProviderOptions,
} from "./ExternalE2EEKeyProvider";
import { Meeting, MeetingEvent } from "./meeting";
import { Participant, ParticipantEvent } from "./participant";
import { AgentParticipant, AgentParticipantEvent } from "./agentParticipant";
import { Stream, StreamEvent } from "./stream";
import { pubSub, message } from "./pubSub";
import { realtimeStore } from "./realtimeStore";
import {
  Errors,
  recordingEvents,
  livestreamEvents,
  hlsEvents,
  transcriptionEvents,
  modes,
  Permission,
  leaveReason,
  BitrateMode,
  reliabilityMode,
  LogLevel,
  AgentState,
} from "./constants";
export {
  Meeting,
  Participant,
  CameraDeviceInfo,
  MicrophoneDeviceInfo,
  PlaybackDeviceInfo,
  DeviceInfo,
  Stream,
  ExternalE2EEKeyProvider,
  E2EEKeyProviderOptions,
  Errors,
  recordingEvents,
  livestreamEvents,
  hlsEvents,
  transcriptionEvents,
  modes,
  Permission,
  leaveReason,
  BitrateMode,
  pubSub,
  realtimeStore,
  message,
  MeetingEvent,
  ParticipantEvent,
  StreamEvent,
  reliabilityMode,
  LogLevel,
  AgentParticipant,
  AgentParticipantEvent,
  AgentState,
};
