export class Participant {
  /**
   * This represents unique ID of the participant who joined the meeting.
   */
  id: string;

  /**
   * This represents display name of the participant.
   */
  displayName: string;

  /**
   * This represents all media streams associated with the participant. Streams could be `audio` , `video` or `share`.
   */
  streams: Map<string, Stream>;

  /**
   * This represents the current quality level of the participant’s video stream.
   */
  quality: "low" | "med" | "high";

  /**
   * This represents the quality level of the participant’s screen-sharing stream.
   */
  screenShareQuality: "low" | "med" | "high";

  /**
   * This indicates whether this participant is the local user.
   *
   * - `true` → Local participant (you)
   * - `false` → Remote participant
   */
  local: boolean;

  /**
   * This represents the current pin state of the participant.
   */
  pinState: {
    cam: boolean;
    share: boolean;
  };

  /**
   * This indicates whether the participant’s webcam is currently enabled.
   */
  webcamOn: boolean;

  /**
   * This indicates whether the participant’s microphone is currently enabled.
   */
  micOn: boolean;

  /**
   * This indicates whether the participant’s screenShare is currently enabled.
   */
  screenShareOn: boolean;
  /**
   * This indicates whether the participant’s screenshare audio is currently enabled.
   *
   */
  screenShareAudioOn: boolean;

  /**
   * This represents the participant’s current mode.
   */
  mode: "SEND_AND_RECV" | "SIGNALLING_ONLY" | "RECV_ONLY";

  /**
   * This represents participant's metadata provided while initializing the meeting
   */
  metaData: object;

  /**
   * - This method can be used to removes the remote participant from the meeting.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.remove();
   * ```
   */
  remove(): void;

  /**
   * - This method can be used to enable the remote participant’s microphone.
   *
   * **Events associated with `enableMic()`:**
   *
   * - The participant first receives a {@link MeetingEvent.mic-requested | mic-requested} event. Once the request is accepted, the microphone is enabled.
   * - All participants receive a {@link ParticipantEvent.stream-enabled | stream-enabled} even containing the corresponding `stream` object.
   *
   * @example
   * ```js
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.enableMic();
   * ```
   */
  enableMic(): void;

  /**
   * - This method can be used to disable the remote participant’s microphone.
   *
   * **Events associated with `disableMic()`:**
   *
   * - All participants receive a {@link ParticipantEvent.stream-disabled | stream-disabled} event containing the corresponding `stream` object.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.disableMic();
   * ```
   */

  disableMic(): void;

  /**
   * - This method can be used to enable the remote participant’s webcam.
   *
   * **Events associated with `enableWebcam()`:**
   *
   * - The participant first receives a {@link MeetingEvent.webcam-requested | webcam-requested} event. Once the request is accepted, the webcam is enabled.
   *
   * - All participants receive a {@link ParticipantEvent.stream-enabled | stream-enabled} event containing the corresponding `stream` object.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.enableWebcam();
   * ```
   */
  enableWebcam(): void;

  /**
   * - This method can be used to disable the remote participant’s webcam.
   *
   * **Events associated with `disableWebcam()`:**
   *
   * - All participants receive a {@link ParticipantEvent.stream-disabled | stream-disabled} event containing the corresponding `stream` object.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.disableWebcam();
   * ```
   */
  disableWebcam(): void;

  /**
   * - This method can be used to set the incoming video quality of the remote participant.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.setQuality("low");
   * ```
   */
  setQuality(quality: "low" | "med" | "high"): void;

  /**
   * - This method can be used to set the quality of the incoming screen-share video of the remote participant.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.setScreenShareQuality("low");
   * ```
   */
  setScreenShareQuality(quality: "low" | "med" | "high"): void;

  /**
   * - This method can be used to adjust the video quality of the remote participant based on the specified viewport dimensions.
   *
   * @param width
   * The width of the viewport used to determine the video quality.
   *
   * @param height
   * The height of the viewport used to determine the video quality.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.setViewPort(300,300);
   * ```
   */
  setViewPort(width: number, height: number): void;

  /**
   * - This method can be used to pin the participant’s camera, screen share, or both.
   *
   * - Every participant receives a {@link MeetingEvent.pin-state-changed | pin-state-changed} event when the pin state is updated.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.pin("CAM");
   * ```
   */
  pin(
    /**
     * Specifies which stream to pin.
     *
     * **Allowed values:**
     * - `"SHARE_AND_CAM"` – Pins both screen share and camera streams.
     * - `"CAM"` – Pins only the camera stream.
     * - `"SHARE"` – Pins only the screen-share stream.
     * @default SHARE_AND_CAM
     */
    type: "SHARE_AND_CAM" | "CAM" | "SHARE"
  ): void;

  /**
   * - This method can be used to unpin the participant’s camera, screen share, or both.
   *
   * - Every participant receives a {@link MeetingEvent.pin-state-changed | pin-state-changed} event when the pin state is updated.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * participant.unpin("CAM");
   * ```
   */
  unpin(
    /**
     *  Specifies which stream to unpin.
     *
     * **Allowed values:**
     * - `"SHARE_AND_CAM"` – Unpins both screen share and camera streams.
     * - `"CAM"` – Unpins only the camera stream.
     * - `"SHARE"` – Unpins only the screen-share stream.
     *
     * @default "SHARE_AND_CAM"
     */
    type: "SHARE_AND_CAM" | "CAM" | "SHARE"
  ): void;

  /**
   * - This method creates and returns a `<div>` element that internally manages the rendering of the participant’s video or screen-share stream.
   * - It allows you to control the rendered stream type, quality preference and styling of both the video element and its container.
   *
   * @param options Optional configuration for rendering the stream.
   *
   * @param options.type
   * Specifies which stream to render.
   *
   * **Allowed value:**
   * - `"video"` – Camera video stream (default)
   * - `"share"` – Screen-share video stream
   *
   * @param options.maxQuality
   * Sets the preferred maximum quality for the rendered stream.
   *
   * **Allowed value:**
   * - `"auto"` – Automatically adapts quality based on network conditions (default)
   * - `"high"` – Highest available quality
   * - `"med"` – Medium quality
   * - `"low"` – Low quality for bandwidth-constrained scenarios
   *
   * @param options.videostyle
   * CSS styles applied directly to the internal `<video>` element.
   *
   * @param options.containerStyle
   * CSS styles applied to the outer container `<div>`.
   *
   * @returns
   * An `HTMLDivElement` containing the rendered video or screen-share stream.
   *
   * @example
   * ```ts
   * const videoElement = participant.renderVideo({
   *   type: "video",
   *   maxQuality: "high",
   *   videostyle: {
   *     objectFit: "cover",
   *     borderRadius: "8px",
   *   },
   *   containerStyle: {
   *     width: "300px",
   *     height: "200px",
   *   },
   * });
   *
   * document.body.appendChild(videoElement);
   * ```
   */
  renderVideo(options?: {
    type?: "video" | "share";
    maxQuality?: "auto" | "high" | "med" | "low";
    videostyle?: Partial<CSSStyleDeclaration>;
    containerStyle?: Partial<CSSStyleDeclaration>;
  }): HTMLDivElement;

  /**
   * - This method creates and returns an `HTMLAudioElement` that can be used to play incoming audio streams in the DOM.
   *
   * @param options
   *
   * @returns
   * An `HTMLAudioElement` that plays the requested audio stream.
   *
   * @example
   * ```ts
   * const audioElement = participant.renderAudio({
   *   type: "audio",
   * });
   *
   * document.body.appendChild(audioElement);
   * ```
   */
  renderAudio(options?: {
    /**
     * **Type:** `"audio" | "shareAudio"`
     *
     * - `"audio"` – Renders the participant’s microphone audio stream.
     * - `"shareAudio"` – Renders the audio stream associated with screen sharing.
     *
     * @default "audio"
     *
     */
    type?: "audio" | "shareAudio";
  }): HTMLAudioElement;

  /**
   * - This method can be used to capture an image from the participant’s current video stream.
   * - The captured image is returned as a Base64-encoded string.
   *
   * @param options
   * @param options.width
   * Desired width of the captured image.
   *
   * @param options.height
   * Desired height of the captured image.
   *
   * @returns
   * A Base64-encoded string representing the captured image, or `null` if
   * the image could not be captured.
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const participant = Array.from(meeting.participants.values())[0];
   * // captureImage returns a Base64 string
   * const base64Data = await participant.captureImage();
   * console.log("base64", base64Data);
   * ```
   */
  captureImage(options?: {
    width?: number;
    height?: number;
  }): Promise<string | null>;

  /**
   * - This method can be used to get detailed statistics about the participant’s video stream.
   * - These metrics provide insights into stream quality, network conditions, and transmission performance at the time the method is called.
   *
   * @returns
   * An array of objects containing the following metrics:
   *
   * - `jitter` – Represents variation in packet arrival time (stream instability).
   * - `bitrate` – The bitrate at which the video stream is being transmitted.
   * - `totalPackets` – Total number of packets transmitted for the stream.
   * - `packetsLost` – Total number of packets lost during transmission.
   * - `rtt` – Round-trip time (in milliseconds) between the client and server.
   * - `codec` – Codec used for encoding the video stream.
   * - `network` – Network type used for transmitting the stream.
   * - `limitation` – Indicates any limitations affecting stream quality.
   * - `size` – Resolution or size information related to the stream.
   *
   * > **Info**
   * >
   * > If the `rtt` value exceeds 300ms, consider switching to a region closer to the user for improved performance. Learn more [visit here](https://docs.videosdk.live/api-reference/realtime-communication/create-room).
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const videoStats = await meeting.localParticipant.getVideoStats();
   * ```
   */
  getVideoStats(): Promise<
    Array<{
      bitrate: number;
      rtt: number;
      network: string;
      codec: string;
      jitter: number;
      limitation: any;
      totalPackets: number;
      packetsLost: number;
      size: any;
      currentSpatialLayer: number;
      currentTemporalLayer: number;
      preferredSpatialLayer: number;
      preferredTemporalLayer: number;
    }>
  >;

  /**
   * - This method can be used to get detailed statistics about the participant’s screen share video stream.
   * - These metrics provide insights into stream quality, network conditions, and transmission performance at the time the method is called.
   *
   * @returns
   * An array of objects containing the following metrics:
   *
   * - `jitter` – Represents variation in packet arrival time (stream instability).
   * - `bitrate` – The bitrate at which the video stream is being transmitted.
   * - `totalPackets` – Total number of packets transmitted for the stream.
   * - `packetsLost` – Total number of packets lost during transmission.
   * - `rtt` – Round-trip time (in milliseconds) between the client and server.
   * - `codec` – Codec used for encoding the video stream.
   * - `network` – Network type used for transmitting the stream.
   * - `limitation` – Indicates any limitations affecting stream quality.
   * - `size` – Resolution or size information related to the stream.
   *
   * > **Info**
   * >
   * > If the `rtt` value exceeds 300ms, consider switching to a region closer to the user for improved performance. Learn more [visit here](https://docs.videosdk.live/api-reference/realtime-communication/create-room).
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const shareStats = await meeting.localParticipant.getShareStats();
   * ```
   */
  getShareStats(): Promise<
    Array<{
      bitrate: number;
      rtt: number;
      network: string;
      codec: string;
      jitter: number;
      limitation: any;
      totalPackets: number;
      packetsLost: number;
      size: any;
      currentSpatialLayer: number;
      currentTemporalLayer: number;
      preferredSpatialLayer: number;
      preferredTemporalLayer: number;
    }>
  >;

  /**
   * - This method can be used to get detailed statistics about the participant’s screen share audio stream.
   * - These metrics provide insights into stream quality, network conditions, and transmission performance at the time the method is called.
   *
   * @returns
   * An array of objects containing the following metrics:
   *
   * - `jitter` – Represents variation in packet arrival time (stream instability).
   * - `bitrate` – The bitrate at which the audio stream is being transmitted.
   * - `totalPackets` – Total number of packets transmitted for the stream.
   * - `packetsLost` – Total number of packets lost during transmission.
   * - `rtt` – Round-trip time (in milliseconds) between the client and server.
   * - `codec` – Codec used for encoding the audio stream.
   * - `network` – Network type used for transmitting the stream.
   *
   * > **Info**
   * >
   * > If the `rtt` value exceeds 300ms, consider switching to a region closer to the user for improved performance. Learn more [visit here](https://docs.videosdk.live/api-reference/realtime-communication/create-room).
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const shareAudioStats = await meeting.localParticipant.getShareAudioStats();
   * ```
   */
  getShareAudioStats(): Promise<
    Array<{
      bitrate: number;
      rtt: number;
      network: string;
      codec: string;
      jitter: number;
      totalPackets: number;
      packetsLost: number;
    }>
  >;

  /**
   * - This method can be used to get detailed statistics about the participant’s audio stream.
   * - These metrics provide insights into stream quality, network conditions, and transmission performance at the time the method is called.
   *
   * @returns
   * An array of objects containing the following metrics:
   *
   * - `jitter` – Represents variation in packet arrival time (stream instability).
   * - `bitrate` – The bitrate at which the audio stream is being transmitted.
   * - `totalPackets` – Total number of packets transmitted for the stream.
   * - `packetsLost` – Total number of packets lost during transmission.
   * - `rtt` – Round-trip time (in milliseconds) between the client and server.
   * - `codec` – Codec used for encoding the audio stream.
   * - `network` – Network type used for transmitting the stream.
   *
   * > **Info**
   * >
   * > If the `rtt` value exceeds 300ms, consider switching to a region closer to the user for improved performance. Learn more [visit here](https://docs.videosdk.live/api-reference/realtime-communication/create-room).
   *
   * @example
   * ```ts
   * let meeting;
   *
   * // Initialize Meeting
   * meeting = VideoSDK.initMeeting({
   *   // ...
   * });
   *
   * const audioStats = await meeting.localParticipant.getAudioStats();
   * ```
   */
  getAudioStats(): Promise<
    Array<{
      bitrate: number;
      rtt: number;
      network: string;
      codec: string;
      jitter: number;
      totalPackets: number;
      packetsLost: number;
    }>
  >;

  /**
   * Registers an event listener.
   * @param eventType Event name to which you want to subscribe.
   * @param listener A callback function that is executed when the specified event is emitted.
   *
   * To view the complete list of available events and their details, refer to {@link ParticipantEvent}.
   */
  on(
    eventType:
      | "stream-enabled"
      | "stream-disabled"
      | "media-status-changed"
      | "video-quality-changed"
      | "stream-paused"
      | "stream-resumed"
      | "e2ee-state-change",
    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 ParticipantEvent}.
   */
  off(
    eventType:
      | "stream-enabled"
      | "stream-disabled"
      | "media-status-changed"
      | "video-quality-changed"
      | "stream-paused"
      | "stream-resumed"
      | "e2ee-state-change",
    listener: (data: any) => void
  ): void;
}

export type ParticipantEvent = {
  /**
   * @event
   * Triggered when a participant’s audio, video, or screen-share {@link Stream} is enabled.
   *
   * @param stream
   * The stream that was enabled.
   *
   * @example
   * ```ts
   * participant.on("stream-enabled", (stream) => {
   *   //
   * });
   * ```
   * @returns
   */
  "stream-enabled": (stream: Stream) => void;

  /**
   * @event
   * Triggered when a participant’s audio, video, or screen-share {@link Stream} is disabled.
   *
   * @param stream
   * The stream that was disabled.
   *
   * @example
   * ```ts
   * participant.on("stream-disabled", (stream) => {
   *   //
   * });
   * ```
   * @returns
   */
  "stream-disabled": (stream: Stream) => void;

  /**
   * @event
   * Triggered when the media status of a participant changes (for example, when audio or video is enabled or disabled).
   *
   * @param data
   *
   * @param data.kind
   * Type of stream whose status changed.
   *
   * @param data.newStatus
   * The updated status of the stream.
   *
   * @example
   * ```ts
   * participant.on("media-status-changed", (data) => {
   *   const { kind, newStatus } = data;
   * });
   * ```
   * @returns
   */
  "media-status-changed": (data: { kind: string; newStatus: string }) => void;

  /**
   * @event
   * - Triggered when the video quality of a participant changes.
   *
   * - The currentQuality and prevQuality values can be `HIGH`, `MEDIUM`, or `LOW`.
   *
   * @param data
   *
   * @param data.currentQuality
   * The updated video quality level.
   *
   * @param data.prevQuality
   * The previous video quality level.
   *
   * @example
   * ```ts
   * participant.on("video-quality-changed", (data) => {
   *   const { currentQuality, prevQuality } = data;
   * });
   * ```
   * @returns
   */
  "video-quality-changed": (data: {
    currentQuality: string;
    prevQuality: string;
  }) => void;

  /**
   * @event
   * - Triggered when a participant’s video, audio, or screen-share stream is paused.
   *
   * - This event is triggered only when the Subscription Manager is enabled by calling the {@link Meeting.enableAdaptiveSubscription | enableAdaptiveSubscription()} method.
   *
   * @param data
   *
   * @param data.kind
   * Type of stream that was paused.
   *
   * @param data.reason
   * Reason why the stream was paused.
   *
   * **Possible values:**
   * - `"muted"` – Stream was paused because it was muted.
   * - `"leastDominance"` – Stream was paused due to bandwidth or dominance rules.
   *
   * @example
   * ```ts
   * participant.on("stream-paused", ({ kind, reason }) => {
   *   console.log(kind, reason);
   * });
   * ```
   * @returns
   */
  "stream-paused": (data: { kind: string; reason: string }) => void;

  /**
   * @event
   * - Triggered when a participant’s video, audio, or screen-share stream is resumed.
   * 
   * - This event is triggered only when the Subscription Manager is enabled by calling the {@link Meeting.enableAdaptiveSubscription | enableAdaptiveSubscription()} method.
   *
   * @param data
   *
   * @param data.kind
   * Type of stream that was resumed.
   *
   * @param data.reason
   * Reason why the stream was resumed.
   *
   * **Possible values:**
   * - `"adaptiveSubscriptionsDisabled"` – Stream resumed after adaptive subscriptions were disabled.
   * - `"networkStable"` – Stream resumed due to stable network conditions.
   *
   * @example
   * ```ts
   * participant.on("stream-resumed", ({ kind, reason }) => {
   *   console.log(kind, reason);
   * });
   * ```
   * @returns
   */
  "stream-resumed": (data: { kind: string; reason: string }) => void;

  /**
   * @event
   * Triggered when the E2EE (End-to-End Encryption) state of a participant’s
   * media stream changes.
   *
   * @param data
   *
   * @param data.kind
   * Type of stream whose E2EE state changed.
   *
   * @param data.state
   * Current E2EE state of the stream.
   *
   * @example
   * ```ts
   * participant.on("e2ee-state-change", (data) => {
   *   console.log("Media kind:", data.kind);
   *   console.log("E2EE state:", data.state);
   * });
   * ```
   * @returns
   */
  "e2ee-state-change": (data: { kind: string; state: string }) => void;
};
import { Stream } from "./stream";
