interface BluetoothDevice {
    readonly id: string;
    readonly name: string | null;
    readonly gatt?: BluetoothRemoteGATTServer;
    addEventListener(
        type: 'gattserverdisconnected',
        listener: EventListener,
    ): void;
    removeEventListener(
        type: 'gattserverdisconnected',
        listener: EventListener,
    ): void;
}

interface BluetoothRemoteGATTServer {
    readonly device: BluetoothDevice;
    readonly connected: boolean;
    connect(): Promise<BluetoothRemoteGATTServer>;
    disconnect(): void;
    getPrimaryService(
        service: string,
    ): Promise<BluetoothRemoteGATTService>;
    getPrimaryServices(): Promise<BluetoothRemoteGATTService[]>;
}

interface BluetoothRemoteGATTService {
    readonly device: BluetoothDevice;
    readonly uuid: string;
    getCharacteristic(
        characteristic: string,
    ): Promise<BluetoothCharacteristic>;
    getCharacteristics(): Promise<BluetoothCharacteristic[]>;
}

interface BluetoothCharacteristic {
    readonly uuid: string;
    readonly service: BluetoothRemoteGATTService;
    readonly properties: BluetoothCharacteristicProperties;
    readValue(): Promise<DataView>;
    writeValueWithResponse(value: BufferSource): Promise<void>;
    writeValueWithoutResponse(value: BufferSource): Promise<void>;
    startNotifications(): Promise<BluetoothCharacteristic>;
    stopNotifications(): Promise<BluetoothCharacteristic>;
}

interface BluetoothCharacteristicProperties {
    readonly broadcast: boolean;
    readonly read: boolean;
    readonly writeWithoutResponse: boolean;
    readonly write: boolean;
    readonly notify: boolean;
    readonly indicate: boolean;
    readonly authenticatedSignedWrites: boolean;
    readonly reliableWrite: boolean;
    readonly writableAuxiliaries: boolean;
}

interface BluetoothRequestDeviceOptions {
    filters?: BluetoothLEScanFilter[];
    optionalServices?: string[];
    acceptAllDevices?: boolean;
}

interface BluetoothLEScanFilter {
    services?: string[];
    name?: string;
    namePrefix?: string;
    manufacturerData?: BluetoothManufacturerDataFilter[];
    serviceData?: BluetoothServiceDataFilter[];
}

interface BluetoothManufacturerDataFilter {
    companyIdentifier: number;
    dataPrefix?: BufferSource;
    mask?: BufferSource;
}

interface BluetoothServiceDataFilter {
    service: string;
    dataPrefix?: BufferSource;
    mask?: BufferSource;
}

interface Navigator {
    bluetooth?: {
        requestDevice(
            options: BluetoothRequestDeviceOptions,
        ): Promise<BluetoothDevice>;
    };
}

interface USBDevice {
    readonly vendorId: number;
    readonly productId: number;
    readonly deviceVersionMajor: number;
    readonly deviceVersionMinor: number;
    readonly deviceVersionSubminor: number;
    readonly manufacturerName: string | null;
    readonly productName: string | null;
    readonly serialNumber: string | null;
    readonly configuration: USBConfiguration | null;
    open(): Promise<void>;
    close(): Promise<void>;
    selectConfiguration(configurationValue: number): Promise<void>;
    claimInterface(interfaceNumber: number): Promise<void>;
    releaseInterface(interfaceNumber: number): Promise<void>;
    transferOut(
        endpointNumber: number,
        data: BufferSource,
    ): Promise<USBOutTransferResult>;
    transferIn(
        endpointNumber: number,
        length: number,
    ): Promise<USBInTransferResult>;
}

interface USBConfiguration {
    readonly configurationValue: number;
    readonly configurationName: string | null;
    readonly interfaces: USBInterface[];
}

interface USBInterface {
    readonly interfaceNumber: number;
    readonly alternate: USBAlternateInterface;
    readonly alternates: USBAlternateInterface[];
}

interface USBAlternateInterface {
    readonly alternateSetting: number;
    readonly interfaceClass: number;
    readonly interfaceSubclass: number;
    readonly interfaceProtocol: number;
    readonly interfaceName: string | null;
    readonly endpoints: USBEndpoint[];
}

interface USBEndpoint {
    readonly endpointNumber: number;
    readonly direction: 'in' | 'out';
    readonly type: 'bulk' | 'interrupt' | 'isochronous' | 'control';
    readonly packetSize: number;
}

interface USBOutTransferResult {
    readonly bytesWritten: number;
    readonly status: 'ok' | 'stall' | 'babble';
}

interface USBInTransferResult {
    readonly data: DataView | null;
    readonly status: 'ok' | 'stall' | 'babble';
}

interface Navigator {
    usb?: {
        requestDevice(
            options: USBRequestDeviceOptions,
        ): Promise<USBDevice>;
    };
}

interface USBRequestDeviceOptions {
    filters: USBDeviceFilter[];
}

interface USBDeviceFilter {
    vendorId?: number;
    productId?: number;
    classCode?: number;
    subclassCode?: number;
    protocolCode?: number;
    serialNumber?: string;
}
