import { NativeEventEmitter } from 'react-native'
import NativeBlePlx from './NativeBlePlx'
import { State, LogLevel, ConnectionPriority } from './TypeDefinition'
import type {
  DeviceId,
  Identifier,
  UUID,
  TransactionId,
  CharacteristicSubscriptionType,
  Base64,
  ScanOptions,
  ConnectionOptions
} from './TypeDefinition'

/**
 * Native device object passed from BleModule.
 * @private
 */
export interface NativeDevice {
  /**
   * Device identifier: MAC address on Android and UUID on iOS.
   * @private
   */
  id: DeviceId
  /**
   * Device name if present
   * @private
   */
  name: string | null
  /**
   * Current Received Signal Strength Indication of device
   * @private
   */
  rssi: number | null
  /**
   * Current Maximum Transmission Unit for this device. When device is not connected
   * default value of 23 is used.
   * @private
   */
  mtu: number

  // Advertisement

  /**
   * Device's custom manufacturer data. Its format is defined by manufacturer.
   * @private
   */
  manufacturerData: Base64 | null

  /**
   * Raw device scan data. When you have specific advertiser data,
   * you can implement your own processing.
   * @private
   */
  rawScanRecord: Base64

  /**
   * Map of service UUIDs with associated data.
   * @private
   */
  serviceData: { [uuid: string]: Base64 } | null

  /**
   * List of available services visible during scanning.
   * @private
   */
  serviceUUIDs: Array<UUID> | null

  /**
   * User friendly name of device.
   * @private
   */
  localName: string | null

  /**
   * Transmission power level of device.
   * @private
   */
  txPowerLevel: number | null

  /**
   * List of solicited service UUIDs.
   * @private
   */
  solicitedServiceUUIDs: Array<UUID> | null

  /**
   * Is device connectable.
   * @private
   */
  isConnectable: boolean | null

  /**
   * List of overflow service UUIDs.
   * @private
   */
  overflowServiceUUIDs: Array<UUID> | null
}

/**
 * Native service object passed from BleModule.
 * @private
 */
export interface NativeService {
  /**
   * Service unique identifier
   * @private
   */
  id: Identifier
  /**
   * Service UUID
   * @private
   */
  uuid: UUID
  /**
   * Device's ID to which service belongs
   * @private
   */
  deviceID: DeviceId
  /**
   * Value indicating whether the type of service is primary or secondary.
   * @private
   */
  isPrimary: boolean
}

/**
 * Native characteristic object passed from BleModule.
 * @private
 */
export interface NativeCharacteristic {
  /**
   * Characteristic unique identifier
   * @private
   */
  id: Identifier
  /**
   * Characteristic UUID
   * @private
   */
  uuid: UUID
  /**
   * Service's ID to which characteristic belongs
   * @private
   */
  serviceID: Identifier
  /**
   * Service's UUID to which characteristic belongs
   * @private
   */
  serviceUUID: UUID
  /**
   * Device's ID to which characteristic belongs
   * @private
   */
  deviceID: DeviceId
  /**
   * True if characteristic can be read
   * @private
   */
  isReadable: boolean
  /**
   * True if characteristic can be written with response
   * @private
   */
  isWritableWithResponse: boolean
  /**
   * True if characteristic can be written without response
   * @private
   */
  isWritableWithoutResponse: boolean
  /**
   * True if characteristic can monitor value changes.
   * @private
   */
  isNotifiable: boolean
  /**
   * True if characteristic is monitoring value changes without ACK.
   * @private
   */
  isNotifying: boolean
  /**
   * True if characteristic is monitoring value changes with ACK.
   * @private
   */
  isIndicatable: boolean
  /**
   * Characteristic value if present
   * @private
   */
  value: Base64 | null
}

/**
 * Native descriptor object passed from BleModule.
 * @private
 */
export interface NativeDescriptor {
  /**
   * Descriptor unique identifier
   * @private
   */
  id: Identifier
  /**
   * Descriptor UUID
   * @private
   */
  uuid: UUID
  /**
   * Characteristic's ID to which descriptor belongs
   * @private
   */
  characteristicID: Identifier
  /**
   * Characteristic's UUID to which descriptor belongs
   * @private
   */
  characteristicUUID: UUID
  /**
   * Service's ID to which descriptor belongs
   * @private
   */
  serviceID: Identifier
  /**
   * Service's UUID to which descriptor belongs
   * @private
   */
  serviceUUID: UUID
  /**
   * Device's ID to which descriptor belongs
   * @private
   */
  deviceID: DeviceId
  /**
   * Descriptor value if present
   * @private
   */
  value: Base64 | null
}

/**
 * Object representing information about restored BLE state after application relaunch.
 * @private
 */
export interface NativeBleRestoredState {
  /**
   * List of connected devices after state restoration.
   * @type {Array<NativeDevice>}
   * @instance
   * @memberof NativeBleRestoredState
   * @private
   */
  connectedPeripherals: Array<NativeDevice>
}

/**
 * Native BLE Module interface
 * @private
 */
export interface BleModuleInterface {
  // NativeModule methods

  addListener(eventType: string): void
  removeListeners(count: number): void

  // Lifecycle

  /**
   * Creates new native module internally. Only one module
   * is allowed to be instantiated.
   * @param {?string} restoreIdentifierKey Optional unique Id used for state restoration of BLE manager.
   * @private
   */
  createClient(restoreIdentifierKey: string | null): void

  /**
   * Debug method to check if BLE restoration components are available.
   * @returns {Promise<{blePlxRestorationAdapterFound: boolean, bleRestorationRegistryFound: boolean, hasRegisterSelector: boolean, initializeWasCalled: boolean}>}
   * @private
   */
  checkRestorationStatus(): Promise<{
    blePlxRestorationAdapterFound: boolean
    bleRestorationRegistryFound: boolean
    hasRegisterSelector: boolean
    initializeWasCalled: boolean
  }>

  /**
   * Destroys previously instantiated module. This function is
   * only safe when previously BleModule was created.
   * @returns {Promise<void>} Promise may return an error when the function cannot be called.
   * @private
   */
  destroyClient(): Promise<void>

  // Monitoring state

  /**
   * Current state of BLE device.
   *
   * @returns {Promise<State>} Current state of BLE device.
   * @private
   */
  state(): Promise<keyof typeof State>

  // Scanning

  /**
   * Starts device scan.
   *
   * @param {?Array<UUID>} filteredUUIDs List of UUIDs for services which needs to be present to detect device during
   * scanning.
   * @param {?ScanOptions} options Platform dependent options
   * @returns {Promise<void>} the promise may be rejected if the operation is impossible to perform.
   * @private
   */
  startDeviceScan(filteredUUIDs: Array<UUID> | null, options: ScanOptions | null): Promise<void>

  /**
   * Stops device scan.
   * @private
   * @returns {Promise<void>} the promise may be rejected if the operation is impossible to perform.
   */
  stopDeviceScan(): Promise<void>

  // Device operations

  /**
   * Request a connection parameter update. This functions may update connection parameters on Android API level 21 or
   * above.
   *
   * @param {DeviceId} deviceIdentifier Device identifier.
   * @param {ConnectionPriority} connectionPriority: Connection priority.
   * @param {TransactionId} transactionId Transaction handle used to cancel operation.
   * @returns {Promise<NativeDevice>} Connected device.
   * @private
   */
  requestConnectionPriorityForDevice(
    deviceIdentifier: DeviceId,
    connectionPriority: ConnectionPriority,
    transactionId: TransactionId
  ): Promise<NativeDevice>

  /**
   * Reads RSSI for connected device.
   *
   * @param {DeviceId} deviceIdentifier Device identifier.
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDevice>} Connected device with updated RSSI value.
   * @private
   */
  readRSSIForDevice(deviceIdentifier: DeviceId, transactionId: TransactionId): Promise<NativeDevice>

  /**
   * Request new MTU value for this device. This function currently is not doing anything
   * on iOS platform as MTU exchange is done automatically. Since Android 14,
   * mtu management has been changed, more information can be found at the link:
   * https://developer.android.com/about/versions/14/behavior-changes-all#mtu-set-to-517
   * @param {DeviceId} deviceIdentifier Device identifier.
   * @param {number} mtu New MTU to negotiate.
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDevice>} Device with updated MTU size. Default value is 23 (517 since Android 14)..
   * @private
   */
  requestMTUForDevice(deviceIdentifier: DeviceId, mtu: number, transactionId: TransactionId): Promise<NativeDevice>

  // Device management

  /**
   * Returns a list of known peripherals by their identifiers.
   * @param {Array<DeviceId>} deviceIdentifiers List of device identifiers
   * @returns {Promise<Array<NativeDevice>>} List of known devices by their identifiers.
   * @private
   */
  devices(deviceIdentifiers: Array<DeviceId>): Promise<Array<NativeDevice>>

  /**
   * Returns a list of the peripherals (containing any of the specified services) currently connected to the system
   * which have discovered services. Returned devices **may not be connected** to your application.
   * @param {Array<UUID>} serviceUUIDs List of service UUIDs. Device must contain at least one of them to be listed.
   * @returns {Promise<Array<NativeDevice>>} List of known devices with discovered services as stated in the parameter.
   * @private
   */
  connectedDevices(serviceUUIDs: Array<UUID>): Promise<Array<NativeDevice>>

  // Connection management

  /**
   * Connect to specified device.
   *
   * @param {DeviceId} deviceIdentifier Device identifier to connect to.
   * @param {?ConnectionOptions} options Connection options.
   * @returns {Promise<NativeDevice>} Connected device.
   * @private
   */
  connectToDevice(deviceIdentifier: DeviceId, options: ConnectionOptions | null): Promise<NativeDevice>

  /**
   * Cancels pending device connection.
   *
   * @param {DeviceId} deviceIdentifier Device identifier which is already connected.
   * @returns {Promise<NativeDevice>} Disconnected device.
   * @private
   */
  cancelDeviceConnection(deviceIdentifier: DeviceId): Promise<NativeDevice>

  /**
   * Checks if specified device is connected.
   *
   * @param {DeviceId} deviceIdentifier Device identifier.
   * @returns {Promise<boolean>} True if specified device is connected.
   * @private
   */
  isDeviceConnected(deviceIdentifier: DeviceId): Promise<boolean>

  // Discovery

  /**
   * Discovers all services, characteristics and descriptors for specified device.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier.
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDevice>} Device which has discovered characteristics and services.
   * @private
   */
  discoverAllServicesAndCharacteristicsForDevice(
    deviceIdentifier: DeviceId,
    transactionId: TransactionId
  ): Promise<NativeDevice>

  // Service and characteristic getters

  /**
   * List of discovered services for specified device.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier.
   * @returns {Promise<Array<NativeService>>} List of services available in device.
   * @private
   */
  servicesForDevice(deviceIdentifier: DeviceId): Promise<Array<NativeService>>

  /**
   * List of discovered characteristics for specified service.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier.
   * @param {UUID} serviceUUID Service UUID which contains characteristics.
   * @returns {Promise<Array<NativeCharacteristic>>} List of characteristics available in service.
   * @private
   */
  characteristicsForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID): Promise<Array<NativeCharacteristic>>

  /**
   * List of discovered characteristics for specified service.
   *
   * @param {Identifier} serviceIdentifier Service ID which contains characteristics.
   * @returns {Promise<Array<NativeCharacteristic>>} List of characteristics available in service.
   * @private
   */
  characteristicsForService(serviceIdentifier: Identifier): Promise<Array<NativeCharacteristic>>

  /**
   * List of discovered descriptors for specified characteristic.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier.
   * @param {UUID} serviceUUID Service UUID which contains descriptors.
   * @param {UUID} characteristicUUID Characteristic UUID which contains descriptors.
   * @returns {Promise<Array<NativeDescriptor>>} List of descriptors available in characteristic.
   * @private
   */
  descriptorsForDevice(
    deviceIdentifier: DeviceId,
    serviceUUID: UUID,
    characteristicUUID: UUID
  ): Promise<Array<NativeDescriptor>>

  /**
   * List of discovered descriptors for specified characteristic.
   *
   * @param {Identifier} serviceIdentifier Service identifier which contains descriptors.
   * @param {UUID} characteristicUUID Characteristic UUID which contains descriptors.
   * @returns {Promise<Array<NativeDescriptor>>} List of descriptors available in characteristic.
   * @private
   */
  descriptorsForService(serviceIdentifier: Identifier, characteristicUUID: UUID): Promise<Array<NativeDescriptor>>

  /**
   * List of discovered descriptors for specified characteristic.
   *
   * @param {Identifier} characteristicIdentifier Characteristic identifier which contains descriptors.
   * @returns {Promise<Array<NativeDescriptor>>} List of descriptors available in characteristic.
   * @private
   */
  descriptorsForCharacteristic(characteristicIdentifier: Identifier): Promise<Array<NativeDescriptor>>

  // Characteristics operations

  /**
   * Read characteristic's value.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier
   * @param {UUID} serviceUUID Service UUID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeCharacteristic>} Characteristic for which value was read
   * @private
   */
  readCharacteristicForDevice(
    deviceIdentifier: DeviceId,
    serviceUUID: UUID,
    characteristicUUID: UUID,
    transactionId: TransactionId
  ): Promise<NativeCharacteristic>

  /**
   * Read characteristic's value.
   *
   * @param {Identifier} serviceIdentifier Service ID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeCharacteristic>} Characteristic for which value was read
   * @private
   */
  readCharacteristicForService(
    serviceIdentifier: Identifier,
    characteristicUUID: UUID,
    transactionId: TransactionId
  ): Promise<NativeCharacteristic>

  /**
   * Read characteristic's value.
   *
   * @param {Identifier} characteristicIdentifer Characteristic ID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeCharacteristic>} Characteristic for which value was read
   * @private
   */
  readCharacteristic(characteristicIdentifer: Identifier, transactionId: TransactionId): Promise<NativeCharacteristic>

  /**
   * Write value to characteristic.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier
   * @param {UUID} serviceUUID Service UUID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {boolean} withResponse True if write should be with response
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeCharacteristic>} Characteristic which saved passed value
   * @private
   */
  writeCharacteristicForDevice(
    deviceIdentifier: DeviceId,
    serviceUUID: UUID,
    characteristicUUID: UUID,
    valueBase64: Base64,
    withResponse: boolean,
    transactionId: TransactionId
  ): Promise<NativeCharacteristic>

  /**
   * Write value to characteristic.
   *
   * @param {Identifier} serviceIdentifier Service ID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {boolean} withResponse True if write should be with response
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeCharacteristic>} Characteristic which saved passed value
   * @private
   */
  writeCharacteristicForService(
    serviceIdentifier: Identifier,
    characteristicUUID: UUID,
    valueBase64: Base64,
    withResponse: boolean,
    transactionId: TransactionId
  ): Promise<NativeCharacteristic>

  /**
   * Write value to characteristic.
   *
   * @param {Identifier} characteristicIdentifier Characteristic ID
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {boolean} withResponse True if write should be with response
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeCharacteristic>} Characteristic which saved passed value
   * @private
   */
  writeCharacteristic(
    characteristicIdentifier: Identifier,
    valueBase64: Base64,
    withResponse: boolean,
    transactionId: TransactionId
  ): Promise<NativeCharacteristic>

  /**
   * Setup monitoring of characteristic value.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier
   * @param {UUID} serviceUUID Service UUID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @param {?CharacteristicSubscriptionType} subscriptionType [android only] subscription type of the characteristic
   * @returns {Promise<void>} Value which is returned when monitoring was cancelled or resulted in error
   * @private
   */
  monitorCharacteristicForDevice(
    deviceIdentifier: DeviceId,
    serviceUUID: UUID,
    characteristicUUID: UUID,
    transactionId: TransactionId,
    subscriptionType: CharacteristicSubscriptionType | null
  ): Promise<void>

  /**
   * Setup monitoring of characteristic value.
   *
   * @param {Identifier} serviceIdentifier Service ID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @param {?CharacteristicSubscriptionType} subscriptionType [android only] subscription type of the characteristic
   * @returns {Promise<void>} Value which is returned when monitoring was cancelled or resulted in error
   * @private
   */
  monitorCharacteristicForService(
    serviceIdentifier: Identifier,
    characteristicUUID: UUID,
    transactionId: TransactionId,
    subscriptionType: CharacteristicSubscriptionType | null
  ): Promise<void>

  /**
   * Setup monitoring of characteristic value.
   *
   * @param {Identifier} characteristicIdentifier Characteristic ID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @param {?CharacteristicSubscriptionType} subscriptionType [android only] subscription type of the characteristic
   * @returns {Promise<void>} Value which is returned when monitoring was cancelled or resulted in error
   * @private
   */
  monitorCharacteristic(
    characteristicIdentifier: Identifier,
    transactionId: TransactionId,
    subscriptionType: CharacteristicSubscriptionType | null
  ): Promise<void>

  // Descriptor operations

  /**
   * Read descriptor's value.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier
   * @param {UUID} serviceUUID Service UUID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {UUID} descriptorUUID Descriptor UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor for which value was read
   * @private
   */
  readDescriptorForDevice(
    deviceIdentifier: DeviceId,
    serviceUUID: UUID,
    characteristicUUID: UUID,
    descriptorUUID: UUID,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  /**
   * Read descriptor's value.
   *
   * @param {Identifier} serviceIdentifier Service identifier
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {UUID} descriptorUUID Descriptor UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor for which value was read
   * @private
   */
  readDescriptorForService(
    serviceIdentifier: Identifier,
    characteristicUUID: UUID,
    descriptorUUID: UUID,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  /**
   * Read descriptor's value.
   *
   * @param {Identifier} characteristicIdentifier Characteristic identifier
   * @param {UUID} descriptorUUID Descriptor UUID
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor for which value was read
   * @private
   */
  readDescriptorForCharacteristic(
    characteristicIdentifier: Identifier,
    descriptorUUID: UUID,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  /**
   * Read descriptor's value.
   *
   * @param {Identifier} descriptorIdentifier Descriptor identifier
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor for which value was read
   * @private
   */
  readDescriptor(descriptorIdentifier: Identifier, transactionId: TransactionId): Promise<NativeDescriptor>

  /**
   * Write value to descriptor.
   *
   * @param {DeviceId} deviceIdentifier Connected device identifier
   * @param {UUID} serviceUUID Service UUID
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {UUID} descriptorUUID Descriptor UUID
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor which saved passed value
   * @private
   */
  writeDescriptorForDevice(
    deviceIdentifier: DeviceId,
    serviceUUID: UUID,
    characteristicUUID: UUID,
    descriptorUUID: UUID,
    valueBase64: Base64,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  /**
   * Write value to descriptor.
   *
   * @param {Identifier} serviceIdentifier Service identifier
   * @param {UUID} characteristicUUID Characteristic UUID
   * @param {UUID} descriptorUUID Descriptor UUID
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor which saved passed value
   * @private
   */
  writeDescriptorForService(
    serviceIdentifier: Identifier,
    characteristicUUID: UUID,
    descriptorUUID: UUID,
    valueBase64: Base64,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  /**
   * Write value to descriptor.
   *
   * @param {Identifier} characteristicIdentifier Characteristic identifier
   * @param {UUID} descriptorUUID Descriptor UUID
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor which saved passed value
   * @private
   */
  writeDescriptorForCharacteristic(
    characteristicIdentifier: Identifier,
    descriptorUUID: UUID,
    valueBase64: Base64,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  /**
   * Write value to descriptor.
   *
   * @param {Identifier} descriptorIdentifier Descriptor identifier
   * @param {Base64} valueBase64 Value to be set coded in Base64
   * @param {TransactionId} transactionId Transaction handle used to cancel operation
   * @returns {Promise<NativeDescriptor>} Descriptor which saved passed value
   * @private
   */
  writeDescriptor(
    descriptorIdentifier: Identifier,
    valueBase64: Base64,
    transactionId: TransactionId
  ): Promise<NativeDescriptor>

  // Background Mode (Android Foreground Service)

  /**
   * Enable background mode using Android foreground service. [Android only]
   * This keeps BLE operations alive when the app is in the background.
   *
   * @param {object} options Configuration options for the foreground service
   * @param {string} options.notificationTitle Title for the notification
   * @param {string} options.notificationText Text content for the notification
   * @returns {Promise<boolean>} True if background mode was enabled successfully
   * @private
   */
  enableBackgroundMode(options: { notificationTitle?: string; notificationText?: string } | null): Promise<boolean>

  /**
   * Disable background mode and stop the foreground service. [Android only]
   *
   * @returns {Promise<boolean>} True if background mode was disabled successfully
   * @private
   */
  disableBackgroundMode(): Promise<boolean>

  /**
   * Update the notification content while background mode is active. [Android only]
   *
   * @param {object} options New notification content
   * @param {string} options.notificationTitle New title for the notification
   * @param {string} options.notificationText New text content for the notification
   * @returns {Promise<boolean>} True if notification was updated successfully
   * @private
   */
  updateBackgroundNotification(
    options: { notificationTitle?: string; notificationText?: string } | null
  ): Promise<boolean>

  /**
   * Check if background mode is currently enabled. [Android only]
   *
   * @returns {Promise<boolean>} True if background mode is enabled
   * @private
   */
  isBackgroundModeEnabled(): Promise<boolean>

  // Other APIs

  /**
   * Cancels specified transaction
   *
   * @param {TransactionId} transactionId Transaction handle for operation to be cancelled
   * @returns {Promise<void>}
   * @private
   */
  cancelTransaction(transactionId: TransactionId): Promise<void>

  /**
   * Sets new log level for native module's logging mechanism.
   * @param {LogLevel} logLevel New log level to be set.
   * @returns {Promise<LogLevel>} Current log level.
   * @private
   */
  setLogLevel(logLevel: keyof typeof LogLevel): Promise<keyof typeof LogLevel | void>

  /**
   * Get current log level for native module's logging mechanism.
   * @returns {Promise<LogLevel>} Current log level.
   * @private
   */
  logLevel(): Promise<keyof typeof LogLevel>

  // Events

  /**
   * New scanned event arrived as [?Error, ?NativeDevice] object.
   * @private
   */
  ScanEvent: string

  /**
   * Characteristic value update broadcasted due to registered notification as
   * [?Error, ?NativeCharacteristic, ?TransactionId].
   * @private
   */
  ReadEvent: string

  /**
   * BLE Manager changed its state as $Keys<typeof State>
   * @private
   */
  StateChangeEvent: string

  /**
   * BLE Manager restored its internal state
   * @private
   */
  RestoreStateEvent: string

  /**
   * Device disconnected as [Error?, NativeDevice]
   * @private
   */
  DisconnectionEvent: string
}

/**
 * Native module provider
 *
 * @private
 */
const NativeBlePlxConstants = NativeBlePlx.getConstants()

export const BleModule: BleModuleInterface = {
  ...NativeBlePlx,
  ...NativeBlePlxConstants
}

export const EventEmitter = NativeEventEmitter
