// 设备信息
export type DeviceInfo = {
  sn: string;                                       // 设备SN号
  versionNumber: number;                            // 固件版本号数字表示，如1.2.3的值就是0x010203
  versionCode: string;                              // 固件版本号的字符串表示，如1.2.3
};

// 电池电量信息
export type BatteryStatus = {
  status: 'idle' | 'charging' | 'full';             // 电池状态，idle：闲置，charging：充电中，full：满电
  battery: number;                                  // 电量百分比，整型，0~100
  voltage: number;                                  // 电池电压，单位：微伏
}

// 常规指令的应答结构，表示指令的结果是成功或是失败
export type ReturnStruct = {
  common: { result: 'failed' | 'success' };
};

// 提示音更新应答
export type ToneUpdateResponse = {
  code: number;                                       // 错误码，0表示成功，1/2/3/4分别表示length-mismatch/busy/card-full/card-error
  result: string;                                     // 错误码的文本表示，与上面的0/1/2/3/4一一对应
}
// UAC更新应答
export type UACUpdateResponse = {
  code: number;                                       // 错误码，0表示成功，1/2/3/4分别表示length-mismatch/busy/card-full/card-error
  result: string;                                     // 错误码的文本表示，与上面的0/1/2/3/4一一对应
}

// 文件信息
export type FileInfo = {
  name: string;                                       // 文件名称
  createDate: string;                                 // 录音日期，yyyy-MM-dd部分
  createTime: string;                                 // 录音时间，HH:mm:ss部分
  time: Date;                                         // 录音时间
  duration: number;                                   // 持续时长，单位为毫秒
  length: number;                                     // 文件长度，单位为字节
  signature: string;                                  // 文件签名，0长度的文件或是录音中的文件的值为000000000000000000000000000000000
};

// 蓝牙状态
export type BluetoothStatus = {
  status: string;                                     // 状态，connected或者disconnected表示是否有连接的设备
  mac?: string;                                       // 当前连接的设备MAC地址
  name?: string;                                      // 当前连接的设备名称
  a2dp?: boolean;                                     // 是否支持A2DP特性
  hfp?: boolean;                                      // 是否支持HFP
  avrcp?: boolean;                                    // 是否支持AVRCP
  battery?: number;                                   // 被连接上的蓝牙耳机的电池电量
};

// 蓝牙设备信息
export type BluetoothDevice = {
  name: string;                                       // 设备名称
  mac: string;                                        // 设备MAC地址
};

// 操作系统枚举
export const enum OS {
  Windows = 'Windows',
  Linux = 'Linux',
  Mac = 'Mac'
}

// 会议平台枚举
export const enum Platform {
  zoom = 'zoom',
  teams = 'teams',
  googleMeeting = 'google-meeting',
  webex = 'webex',
  feishu = 'feishu',
  lark = 'lark',
  wechat = 'wechat',
  line = 'line',
  whatsApp = 'whats-app',
  slack = 'slack',
  discord = 'discord'
}

// 日历行程信息
export type ScheduleInfo = {
  startDate: Date;                                      // 开始时间(注意是时间)
  endDate: Date;                                        // 结束时间
  os: OS;                                               // 操作系统
  platform: Platform;                                   // 会议软件平台
};

// 日志级别枚举
export enum Level {
  debug = 'debug',
  info = 'info',
  error = 'error'
}

// 日志条目信息
export type Log = {
  level: Level;                                         // 级别，如info/debug/error
  module: string;                                       // 日志发生时所处的模块
  procedure: string;                                    // 日志发生时所处的过程
  message: string;                                      // 日志详情
  time: number;                                         // 日志发生时间的时间戳
};

// 日志记录管理
export type Logger = {
  // 历史日志条目，有最大保留数量上限
  messages: Log[];
  // 是否开启控制台输出
  consoleOutput: boolean;
  // 分级日志记录
  info(module: string, procedure: string, message: string): void;
  debug(module: string, procedure: string, message: string): void;
  error(module: string, procedure: string, message: string): void;
  _append(level: Level, module: string, procedure: string, message: string): void;
  _print(log: Log): void;
  // 过滤查找
  filter(module: string, procedure: string): void;
  // 启停控制台输出
  enableConsoleOutput(): void;
  disableConsoleOutput(): void;
  // 查看最后rows条记录
  peek(rows: number): void;
  // 按照module和procedure、keyword搜索日志
  search(module: string, procedure: string, keyword: string): Log[];
};

// HiDock连接及协议交互类实现
// 构造方法增加了conn参数，用于兼容单设备连接和多设备连接时的过渡
// 以后会只保留多设备连接，也就是USBDevice实例由外部的代码进行管理，Jensen类只负责收发消息和消息的处理
declare class Jensen {
  // 构造方法，logger为外部传入的全局共用的Logger实例；如果传入了conn，就表示连接管理交由外部代码管理
  constructor(log?: Logger, conn?: USBDevice);
  // 连接初始化，不需要显式调用
  init: () => Promise<boolean>;
  // 连接初始化（多连接时适用）
  initialize: () => Promise<boolean>;
  // 发起连接设备请求（单连接时适用）
  connect: () => Promise<void>;
  // 事件：当连接完成时触发
  onconnect: () => void;
  // 主动断开连接（单连接时适用）
  disconnect: () => void;
  // 事件：当连接断开时触发
  ondisconnect?: () => void;
  // 连接重置（多连接时适用）
  reconnect: () => Promise<boolean>;
  // 获取USBDevice实例
  getUSBDevice: () => USBDevice;
  // 更新USBDevice实例
  setUSBDevice: (dev: USBDevice) => void;
  // 是否停止连接检查（OTA更新时使用）
  isStopConnectionCheck: boolean;
  // 是否已连接
  isConnected: () => boolean;
  // 获取当前连接的设备型号，如hidock-h1/hidock-h1e/hidock-p1/hidock-p1:mini等
  getModel: () => string;
  // 尝试自动连接（单连接时适用）
  tryconnect: (disableOnConnect?: boolean) => Promise<boolean>;

  // ----------------------------------------------------------------------------
  // 从此处往下全部是与设备通信的消息指令实现

  // 获取设备信息
  getDeviceInfo: (time?: number) => Promise<DeviceInfo>;

  // 列出设备录音文件
  listFiles: (time?: number) => Promise<FileInfo[]>;

  // 获取录音文件内容
  // #fileName 为文件名称
  // #length 文件长度
  // #on 回调为当数据准备好时调用，如果传输失败会传递fail过来
  // #onprogress 回调为传输时进度发生变化时调用
  // 注意：文件传输进度和数据并不是同时到达的，在文件传输到100%时才会开始调用on回调进行转移数据
  getFile: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void;

  // 获取指定长度的录音文件内容，length参数可以小于或等于文件的原始长度，其它参数与getFile()方法一致
  getFilePart: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void;
  
  // 暂不使用
  getFileBlock: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void) => Promise<ReturnStruct['common']>;

  // 录音文件随机读取，从指定位置起读取指定数量个字节
  readFile: (fname: string, offset: number, length: number) => Promise<Uint8Array>;

  // 传输文件
  transferFile: (filename: string, length: number, ondata: (msg: Uint8Array | 'fail') => void, seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 请求固件更新
  // #versionNumber 新固件的版本号
  // #length 新固件的内容长度
  // #time 超时时长
  requestFirmwareUpgrade: (versionNumber: number, length: number, time?: number) => Promise<{ result: 'accepted' | 'fail' }>;

  // 获取电池电量信息
  getBatteryStatus: (time?:number) => Promise<BatteryStatus>;

  // 发送新固件内容到设备端
  // #data 为固件数据内容
  // #seconds 为超时时长
  // #onProgress 为进度回调
  uploadFirmware: (data: number[], seconds?: number, onProgress?: (cur: number, total: number) => void) => Promise<ReturnStruct['common']>;

  // 开始BNC体验
  beginBNC: (time?: number) => Promise<ReturnStruct['common']>;
  // 停止BNC体验
  endBNC: (time?: number) => Promise<ReturnStruct['common']>;

  // 设置设备时间
  setTime: (date: Date, timeout?: number) => Promise<ReturnStruct['common']>;

  // 删除文件
  deleteFile: (fileName: string) => Promise<{ result: 'failed' | 'success' | 'not-exists' }>;

  // 获取设备时间
  getTime: (time?: number) => Promise<{ time: string }>;

  // 获取设备设置项，注意：不同型号的设备有不同的设置项
  getSettings: (time?: number) => Promise<{ autoRecord: boolean; autoPlay: boolean; notification?: boolean } | null>;

  // 设备Auto Record开关
  setAutoRecord: (enable: boolean, time?: number) => Promise<ReturnStruct['common']>;

  // 设置Recording Notification提示音开关，录音开始时是否播放Start Recording
  setAutoPlay: (enable: boolean, time?: number) => Promise<ReturnStruct['common']>;
  
  // 设置WebUSB设备接入提示（Windows电脑右下角的弹窗）
  setNotification: (state: boolean, time?: number) => Promise<ReturnStruct['common']>;

  // 获取录音中的文件信息，当它从null -> non-null -> null转变时就表示已经有一个新的录音产生了
  getRecordingFile: () => Promise<{ recording: null | string; createTime: string; createDate: string }>;
  
  // 获取内部存储卡信息
  // used：已使用，capacity：总容量（单位为M），status：900表示正常，其它表示异常
  getCardInfo: (seconds?: number) => Promise<{ used: number; capacity: number; status: string }>;

  // 内部存储卡格式化
  formatCard: (seconds?: number) => Promise<ReturnStruct['common']>;

  // 恢复出厂设置，MTT阶段添加，不建议使用
  factoryReset: (seconds?: number) => Promise<ReturnStruct['common']>;

  // 恢复出厂设置，内部存储格式化，设置项恢复默认值，蓝牙配对信息清空等
  restoreFactorySettings: (seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 获取设备录音文件数量
  getFileCount: (seconds?: number) => Promise<{ count: number } | null>;
  
  // 录音测试，MTT阶段使用，不应该在HiNotes上使用
  recordTestStart: (type: number, seconds?: number) => Promise<ReturnStruct['common']>;
  recordTestEnd: (type: number, seconds?: number) => Promise<ReturnStruct['common']>;

  // 测试消息，用于确定是否能够正常通信，已作废
  test: (seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 设置蓝牙提示音开关
  setBluetoothPromptPlay: (state: boolean, seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 写入/更新设备内SN号
  writeSerialNumber: (sn: string) => Promise<ReturnStruct['common']>;
  
  // 发送会议日程信息，设备将在指定的时间上去模拟会议软件的按键，来实现对接听和挂断的兼容
  sendScheduleInfo: (info: ScheduleInfo[]) => Promise<ReturnStruct['common']>;
  
  // 扫描蓝牙设备，此方法大约需要30秒才有返回，需要做好等待提示
  scanDevices: (seconds?: number) => Promise<BluetoothDevice[]>;
  
  // 连接到指定的蓝牙设备
  connectBTDevice: (mac: string, seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 断开已连接的蓝牙设备
  disconnectBTDevice: (seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 获取蓝牙连接状态
  getBluetoothStatus: (seconds?: number) => Promise<BluetoothStatus>;
  
  // 获取实时音频流的设置信息，主要是确定设备端的实时音频的编码信息
  getRealtimeSettings: () => Promise<any>;
  
  // 开始实时音频流传输
  startRealtime: () => Promise<ReturnStruct['common']>;
  
  // 暂停实时音频流传输
  pauseRealtime: () => Promise<ReturnStruct['common']>;
  
  // 停止/结束实时音频流传输
  stopRealtime: () => Promise<ReturnStruct['common']>;
  
  // 获取实时音频流数据
  getRealtime: (frames: number) => Promise<{ data: Uint8Array; rest: number }>;
  
  // 请求设备提示音更新
  requestToneUpdate: (signature: string, size: number, seconds?: number) => Promise<ToneUpdateResponse>;
  
  // 更新设备提示音
  updateTone: (data: Uint8Array, seconds?: number) => Promise<ReturnStruct['common']>;
  
  // 请求设备UAC固件更新
  requestUACUpdate: (signature: string, size: number, seconds?: number) => Promise<UACUpdateResponse>;
  
  // 更新设备UAC固件
  updateUAC: (data: Uint8Array, seconds?: number) => Promise<ReturnStruct['common']>;

}

export = Jensen;
