import {
  JazzSdkOptions,
  JazzSdk,
  JazzActivityEvent,
  JazzRoomEventParticipantLeft,
  JazzRoomEventParticipantJoined,
  JazzRoomEventParticipantUpdate,
  JazzRoomEventParticipants,
  JazzRoomEventLocalParticipantChanged,
  JazzRoomEventLocalParticipantId,
  JazzRoomEventDisconnecting,
  JazzRoomParticipantId,
  MediaType,
  JazzSdkAdditionalPlugins,
} from '@salutejs/jazz-sdk-web';
import { Container } from 'ditox';

/**
 * Creates Jazz SDK for electron applications.
 */
declare function createJazzSdkElectron(
  options?: JazzSdkOptions,
): Promise<JazzSdk>;

type TransportEventRegisterEndpoint = {
  type: 'registerEndpoint';
  payload: {
    endpointName: string;
  };
};
type TransportEventUnregisterEndpoint = {
  type: 'unregisterEndpoint';
  payload: {
    endpointName: string;
  };
};
type TransportEventHandsRaised = {
  type: 'handsRaised';
  payload: {
    handsRaised: JazzRoomParticipantId[];
  };
};
type NotificationAction = {
  id: string;
  view?:
    | 'clear'
    | 'default'
    | 'secondary'
    | 'accent'
    | 'warning'
    | 'dark'
    | 'primary'
    | 'success'
    | 'critical'
    | 'black'
    | 'white';
  text: string;
  size?: 's' | 'm' | 'l' | 'xs' | 'lr' | 'mr' | 'sr' | 'xsr' | 'xxs';
  stretching?: 'filled' | 'fixed' | 'auto';
  data: Record<string, unknown>;
};
type TransportEventNotificationOpen = {
  type: 'notification:open';
  payload: {
    id: string;
    title?: string;
    content?: string;
    actions?: NotificationAction[];
    icon?: string;
    iconPlacement?: 'left' | 'top';
    showCloseIcon?: boolean;
    timeout?: number;
  };
};
type TransportEventNotificationClose = {
  type: 'notification:close';
  payload: {
    id: string;
  };
};
type TransportEventNotificationInvokeAction = {
  type: 'notification:invokeAction';
  payload: {
    id: string;
    data: Record<string, unknown>;
  };
};
type TransportLocalTrackManagerEventAddTrack = {
  type: 'localTrackManager:addTrack';
  payload: {
    isMuted: boolean;
    mediaType: MediaType;
    streamId: string;
  };
};
type TransportLocalTrackManagerEventMuteTrackChanged = {
  type: 'localTrackManager:muteTrackChanged';
  payload: {
    isMuted: boolean;
    mediaType: MediaType;
    streamId: string;
  };
};
type TransportLocalTrackManagerEventLocalTrackUpdated = {
  type: 'localTrackManager:localTrackUpdated';
  payload: {
    isMuted: boolean;
    mediaType: MediaType;
    streamId: string;
  };
};
type TransportLocalTrackManagerEventLocalTrackRemove = {
  type: 'localTrackManager:removeTrack';
  payload: {
    mediaType: MediaType;
    streamId: string;
  };
};
type TransportLocalTrackManagerEventLocalTrackDispose = {
  type: 'localTrackManager:disposeTrack';
  payload: {
    mediaType: MediaType;
    streamId: string;
  };
};
type TransportRoomTrackManagerEventRemoteTrackInfo = {
  type: 'roomTrackManager:remoteTrackInfo';
  payload: {
    isMuted: boolean;
    participantId: JazzRoomParticipantId;
    mediaType: MediaType;
  };
};
type TransportRoomTrackManagerEventAddTrack = {
  type: 'roomTrackManager:addTrack';
  payload: {
    isMuted: boolean;
    participantId: JazzRoomParticipantId;
    mediaType: MediaType;
    streamId: string;
    isLocal: boolean;
  };
};
type TransportRoomTrackManagerEventTrackMuteChanged = {
  type: 'roomTrackManager:trackMuteChanged';
  payload: {
    isMuted: boolean;
    participantId: JazzRoomParticipantId;
    mediaType: MediaType;
    streamId: string;
    isLocal: boolean;
  };
};
type TransportRoomTrackManagerEventRemoveTrack = {
  type: 'roomTrackManager:removeTrack';
  payload: {
    participantId: JazzRoomParticipantId;
    mediaType: MediaType;
    streamId: string;
    isMuted: boolean;
    isLocal: boolean;
  };
};
type TransportRoomTrackManagerEventLocalTrackUpdated = {
  type: 'roomTrackManager:trackUpdated';
  payload: {
    isMuted: boolean;
    mediaType: MediaType;
    streamId: string;
    participantId: JazzRoomParticipantId;
    isLocal: boolean;
  };
};
type TransportEvent = (
  | JazzActivityEvent
  | JazzRoomEventParticipantLeft
  | JazzRoomEventParticipantJoined
  | JazzRoomEventParticipantUpdate
  | JazzRoomEventParticipants
  | JazzRoomEventLocalParticipantChanged
  | JazzRoomEventLocalParticipantId
  | JazzRoomEventDisconnecting
  | TransportEventRegisterEndpoint
  | TransportEventUnregisterEndpoint
  | TransportEventUnregisterEndpoint
  | TransportEventHandsRaised
  | TransportEventNotificationOpen
  | TransportEventNotificationClose
  | TransportEventNotificationInvokeAction
  | TransportLocalTrackManagerEventAddTrack
  | TransportLocalTrackManagerEventMuteTrackChanged
  | TransportLocalTrackManagerEventLocalTrackUpdated
  | TransportLocalTrackManagerEventLocalTrackRemove
  | TransportLocalTrackManagerEventLocalTrackDispose
  | TransportRoomTrackManagerEventAddTrack
  | TransportRoomTrackManagerEventTrackMuteChanged
  | TransportRoomTrackManagerEventRemoveTrack
  | TransportRoomTrackManagerEventLocalTrackUpdated
  | TransportRoomTrackManagerEventRemoteTrackInfo
) &
  EventLike;
/**
 * experimental
 */
type TransportInvokeEvent =
  | {
      type: 'someType1';
      payload: {
        foo: 'bar';
      };
      response: {
        bar: 'foo';
      };
    }
  | {
      type: 'someType2';
      response: {
        bar: 'foo';
      };
    };
type EventLike = {
  type: string;
  to?: string;
};
type EventLikeWithResponse = {
  type: string;
  payload?: unknown;
  response: unknown;
};
type EventLikeWithResponsePayload = {
  type: string;
  payload: unknown;
  response: unknown;
};
type TransportService<
  M extends EventLike = TransportEvent,
  I extends EventLikeWithResponse = TransportInvokeEvent,
> = {
  once: <
    Type extends M['type'],
    Result extends M & {
      type: Type;
    },
  >(
    key: Type,
    callback: (
      ...args: Result extends {
        payload: infer S;
      }
        ? [S]
        : []
    ) => void,
  ) => () => void;
  on: <
    Type extends M['type'],
    Result extends M & {
      type: Type;
    },
  >(
    key: Type,
    callback: (
      ...args: Result extends {
        payload: infer S;
      }
        ? [S]
        : []
    ) => void,
  ) => () => void;
  off: <
    Type extends M['type'],
    Result extends M & {
      type: Type;
    },
  >(
    key: Type,
    callback: (
      ...args: Result extends {
        payload: infer S;
      }
        ? [S]
        : []
    ) => void,
  ) => void;
  /**
   * reference to "on"
   */
  subscribe: <
    Type extends M['type'],
    Result extends M & {
      type: Type;
    },
  >(
    key: Type,
    callback: (
      ...args: Result extends {
        payload: infer S;
      }
        ? [S]
        : []
    ) => void,
  ) => () => void;
  addListener: <
    Type extends M['type'],
    Result extends M & {
      type: Type;
    },
  >(
    key: Type,
    callback: (
      ...args: Result extends {
        payload: infer S;
      }
        ? [S]
        : []
    ) => void,
  ) => void;
  /**
   * reference to "off"
   */
  removeListener: <
    Type extends M['type'],
    Result extends M & {
      type: Type;
    },
  >(
    key: Type,
    callback: (
      ...args: Result extends {
        payload: infer S;
      }
        ? [S]
        : []
    ) => void,
  ) => void;
  send: (event: M) => void;
  /**
   * experimental
   */
  __invoke: <
    Type extends I['type'],
    Payload extends I & {
      type: Type;
    },
    Response extends (I & {
      type: Type;
    })['response'],
  >(
    params: Payload extends EventLikeWithResponsePayload
      ? {
          type: Type;
          payload: Payload['payload'];
        }
      : {
          type: Type;
        },
  ) => Promise<Response>;
  withType: <
    S extends EventLike | undefined | void | null,
    O extends EventLikeWithResponse | undefined | void | null = void,
  >() => S extends EventLike
    ? O extends EventLikeWithResponse
      ? TransportService<M | S, I | O>
      : TransportService<M | S, I>
    : O extends EventLikeWithResponse
      ? TransportService<M, I | O>
      : TransportService<M, I>;
};

type JazzSdkElectronBridge = {
  transport: TransportService;
};

type JazzSdkElectronEndpointOptions = Readonly<{
  container?: Container;
  /** Extensions for the SDK */
  plugins?: JazzSdkAdditionalPlugins;
  endpointName: string;
  bridge?: () => JazzSdkElectronBridge;
}>;
type JazzSdkElectronEndpoint = Readonly<{
  container: Container;
  destroy: () => void;
}>;

/**
 * Creates Jazz SDK for browserWindows of electron.
 */
declare function createJazzSdkElectronEndpoint(
  options: JazzSdkElectronEndpointOptions,
): Promise<JazzSdkElectronEndpoint>;

export {
  type JazzSdkElectronEndpoint,
  type JazzSdkElectronEndpointOptions,
  createJazzSdkElectron,
  createJazzSdkElectronEndpoint,
};
