import { ble, constant } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';

export class BleManager {
  // 需要扫描的蓝牙设备
  mac: string = ""
  // mtu设置
  mtu: number = 500
  // 是否已经查找到
  isFindDevice: boolean = false
  // 当前持有的蓝牙设备
  bleDevice: ble.ScanResult | undefined = undefined
  // gatt连接对象
  bleGatt: ble.GattClientDevice | undefined = undefined

  constructor(mac: string) {
    this.mac = mac
  }

  /**
   * 蓝牙扫描监听
   */
  private onReceiveEvent = (data: Array<ble.ScanResult>) => {
    // console.info("BleManager", 'BLE scan device find result: ' + JSON.stringify(data));
    if (this.isFindDevice == true) {
      return
    }
    data.forEach((device) => {
      const byteArray = new Uint8Array(device.data.slice(49, 55))
      let findMac = ""
      for (let idx = 0; idx < byteArray.length; idx++) {
        const byte = byteArray[idx]
        findMac += byte.toString(16).padStart(2, "0").toUpperCase()
        // 拼接:操作
        if ((idx + 1) != byteArray.length) {
          findMac += ":"
        }
      }
      // console.log("BleManager", "data info ", findMac)
      if (this.isFindDevice != true && findMac == this.mac) {
        console.log("BleManager", "onReceiveEvent() find mac ", findMac, "device")
        this.isFindDevice = true
        this.bleDevice = device
        this.stopScan()
        this.innerConnect()
        return
      }
    })
  }
  /**
   * 蓝牙连接状态监听
   */
  private onBleConnectionStateChanged = (state: ble.BLEConnectionChangeState) => {
    let status: ble.ProfileConnectionState = state.state;
    console.info("BleManager", 'clientConnectStateChanged() connect state changed', status)
    if (status == constant.ProfileConnectionState.STATE_CONNECTED) {
      this.bleGatt?.getServices().then((services) => {
        console.log("BleManager", "clientConnectStateChanged() getServices()", JSON.stringify(services))
        // 发现完服务，设置mtu
        try {
          this.bleGatt?.setBLEMtuSize(this.mtu)
        } catch (error) {
          console.error("BleManager", "onBleConnectionStateChanged() setBLEMtuSize() failed", JSON.stringify(error))
        }
      }).catch(() => {
      })
    } else if (status == constant.ProfileConnectionState.STATE_DISCONNECTED) {
      // 断开连接的操作
      this.disconnect()
    }
  }
  /**
   * 特征变化监听
   */
  private onBleCharacteristicChanged = (ch: ble.BLECharacteristic) => {
    console.log("BleManager", "onBleCharacteristicChanged()", JSON.stringify(ch))
  }
  /**
   * 设置Mtu变化监听
   */
  private onBleMtuChanged = (mtu: number) => {
    console.log("BleManager", "onBleMtuChanged()", mtu)
  }

  /**
   * 执行蓝牙扫描和连接操作
   */
  connect() {
    this.scan()
  }

  disconnect() {
    try {
      this.bleGatt?.off("BLEConnectionStateChange", this.onBleConnectionStateChanged)
      this.bleGatt?.on("BLECharacteristicChange", this.onBleCharacteristicChanged)
      this.bleGatt?.off("BLEMtuChange", this.onBleMtuChanged)
      this.bleGatt?.disconnect()
      this.bleGatt?.close()
    } catch (e) {
    }
  }

  /**
   * 蓝牙扫描操作
   */
  private scan() {
    try {
      ble.on("BLEDeviceFind", this.onReceiveEvent)
      ble.startBLEScan([{}], { dutyMode: ble.ScanDuty.SCAN_MODE_LOW_LATENCY })
      console.log("BleManager", "scan() startBLEScan() success")
    } catch (err) {
      console.error("BleManager", 'scan() failed errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
    }
  }

  /**
   * 停止查找设备并移除扫描监听
   */
  private stopScan() {
    try {
      ble.off("BLEDeviceFind", this.onReceiveEvent)
      ble.stopBLEScan()
      console.log("BleManager", "stopScan() stopBLEScan() success")
    } catch (error) {
      console.log("BleManager", "stopScan() stopBLEScan() failed " + JSON.stringify(error))
    } finally {
      this.isFindDevice = false
    }
  }

  /**
   * 连接蓝牙设备
   */
  private innerConnect() {
    try {
      this.bleGatt = ble.createGattClientDevice(this.bleDevice?.deviceId ?? "")
      this.bleGatt?.on("BLEConnectionStateChange", this.onBleConnectionStateChanged)
      this.bleGatt?.on("BLECharacteristicChange", this.onBleCharacteristicChanged)
      this.bleGatt?.on("BLEMtuChange", this.onBleMtuChanged)
      this.bleGatt?.connect()
      console.log("BleManager", "innerConnect() connect to", this.mac, "success")
    } catch (e) {
      console.log("BleManager", "innerConnect() can`t connect to", this.bleDevice?.deviceId, "error ", JSON.stringify(e))
    }
  }
}