import * as tools from "./tools"
import {inArray, isObject, logs, sleep} from "../util";
import {showToast} from "../app";
import {checkBleAuth} from "../uniFunction";
import {ab2hex, stringToArrayBuffer} from "./hex";
import {isH5} from "@/utils/platform";
import Vue from "vue";

/**
 * 蓝牙工具类
 * 封装小程序蓝牙流程方法
 * 处理事件通信
 */
export class bleBase {

  constructor(topClass) {
    this.topClass = topClass
    this.typeKey = ''
    this.option = {}
    this.deviceId = null
    this.serviceId = null
    this.writeId = null // 写入id
    this.characteristicId = null// 接收id
  }

  /**
   * 搜索蓝牙设备
   * @param data
   * @param op
   * @param showLoad
   * @returns {Promise<unknown>}
   */
  getList(data = {}, op = {}, showLoad = true) {
    let option = {
      second: 5000,
      type: 1,
      fun: null,
    }
    option = Object.assign(option, op)
    return new Promise(async (resolve, reject) => {
      logs('进入 searchBle')
      try {
        await this.topClass.init()
        if (isH5) throw 'H5不支持蓝牙功能'
        await checkBleAuth() // 检查用户蓝牙授权是否通过
        if (showLoad) uni.showLoading({title: '搜索设备中。。。'})
        await tools._startSearch(Object.assign({
          allowDuplicatesKey: true
        }, data))
        let list = await this.bluetoothDeviceFound(option.second, option.type, option.fun)
        if (showLoad) uni.hideLoading()
        resolve(Object.values(list))
      } catch (msg) {
        if (showLoad) uni.hideLoading()
        showToast(msg, 4000)
        resolve(new Object())
      }
    })
  }

  /**
   * 过滤并转换附加参数   ok 表示 是否通过过滤
   * @param item
   * @returns item
   */
  filter(item) {
    item.ok = false
    if (this.option.top) {
      let index = item.manufacturerData.search(this.option.top)
      if (this.option.indexJudge) item.ok = this.option.indexJudge(index)
    } else {
      item.ok = true
    }
    if (item.ok && this.option.macSlice) item.mac = item.manufacturerData.slice(...this.option.macSlice)
    if (this.option.search && !inArray(item.mac, this.option.machine)) item.ok = !1
    return item
  }

  /**
   * 过滤设备信息
   * @param second
   * @param type              1 普通模式（只过滤是否符合）；
   *                          2 指定模式（只有找到一个就会结束，但因为搜索未完全结束可能会返回多个的情况）
   *                          3 无限模式
   * @param fun
   * @returns {Promise<unknown>}
   */
  bluetoothDeviceFound(second = 5000, type = 1, fun = null) {
    let list = {}
    return new Promise(async (resolve, reject) => {
      try {
        this.topClass.bleDeviceFound((res) => {
          res.devices.forEach((item) => {
            item.manufacturerData = ab2hex(item.advertisData)
            item = this.filter(item)
            if (item.ok) {
              list[item.deviceId] = item
              if (type == 2) {
                tools._stopSearchBluetooth();
                throw '已找到设备'
              } else if (type == 3 && fun) {
                fun({
                  run: true,
                  data: item,
                })
              }
            }
          })
        })
        if (second > 0) {
          await sleep(second)
          throw '搜索结束'
        }
      } catch (error) {
        if (type != 3) {
          await tools._stopSearchBluetooth();
        } else if (type == 3 && fun) {
          fun({
            run: false,
          })
        }
        this.topClass.bleDeviceFound(null)
        return resolve(Object.values(list))
      }
    })
  }

  async startSearch(data) {
    await tools._startSearch(Object.assign({
      allowDuplicatesKey: true
    }, data))
  }

  stopSearch() {
    /* #ifndef H5 */
    tools._stopSearchBluetooth();
    /* #endif */
  }


  //  二、 蓝牙连接  根据某一id连接设备，4.0
  async connectionBle(deviceId) {
    try {
      if (isH5) throw 'H5无法运行'
      if (this.deviceId && this.deviceId == deviceId) {
        logs('同一台设备，跳出')
        return Promise.resolve() // 已连接设备与当前为同一台
      }

      if (this.deviceId && this.deviceId != deviceId) {
        logs('有旧设备，关闭旧设备中')
        await this.closeConnection() // 结束前一台
        await sleep(500)
      }
      this.topClass.addConnect(deviceId, this.typeKey)
      this.deviceId = deviceId
      logs('connectBle --- ' + this.deviceId)
      await tools._connectBlue(this.deviceId)
      await sleep(2000);
      await this.getBLEServices(this.option.serviceKey)
      await this.getCharacteristics(this.option.channelKey)
      await tools._notifyBLECharacteristicValueChange(this.deviceId, this.serviceId, this.characteristicId)
      return Promise.resolve()
    } catch (e) {
      await this.closeConnection()
      console.log('connectionBle catch', e)
      return Promise.reject('连接失败')
    }
  }

  async getBLEServices(serviceKey) {
    logs('开始蓝牙获取服务')
    let servicesList = await tools._getBLEServices(this.deviceId)
    if (!servicesList) throw '链接失败，蓝牙未找到服务号'
    logs('开始蓝牙获取服务', servicesList)
    for (let i = 0; i < servicesList.services.length; i++) {
      if (servicesList.services[i].isPrimary && (servicesList.services[i].uuid.indexOf(serviceKey) != -1)) {
        this.serviceId = servicesList.services[i].uuid
        return;
      }
    }
  }

  async getCharacteristics(channelKey = '') {
    logs('开始蓝牙通道信息')
    // 获取通道信息（读、写、监听）
    let writeKey = ''
    let notifyKey = ''
    if (isObject(channelKey)) {
      writeKey = channelKey.writeKey
      notifyKey = channelKey.notifyKey
    } else {
      writeKey = notifyKey = channelKey
    }
    let {characteristics} = await tools._getCharacteristics(this.deviceId, this.serviceId)
    logs(`开始蓝牙通道信息 writeKey:${writeKey} notifyKey:${notifyKey} characteristics:${characteristics}`)

    for (let i = 0; i < characteristics.length; i++) {
      let item = characteristics[i];
      if (item.uuid.search(writeKey) != -1) {
        this.writeId = item.uuid // 写入id
      }
      if (item.uuid.search(notifyKey) != -1) {
        this.characteristicId = item.uuid // 写入id
      }
    }
    logs(`开始蓝牙通道信息 writeId:${this.writeId} characteristicId:${this.characteristicId}`)
  }


  /**
   * 关闭设备连接
   * @param deviceId
   * @returns {Promise<void>}
   */
  async closeConnection(deviceId = '') {
    if (!deviceId) deviceId = this.deviceId
    // 断开已连接的连接
    try {
      if (this.deviceId) await tools._closeBLEConnection(deviceId);
    } catch (e) {
    }
    this.deviceId = null
    this.serviceId = null
    this.writeId = null
    this.characteristicId = null
    this.topClass.delConnect(deviceId)
  }


  async sentOrder(str, type = 1) {
    let buffer = type != 0 ? stringToArrayBuffer(str, type) : str
    logs("-- 发送数据: ", ab2hex(buffer, ' '))
    try {
      /* #ifndef H5 */
      if (this.deviceId) await tools._writeBLECharacteristicValue(this.deviceId, this.serviceId, this.writeId, buffer)
      /* #endif */
      return true
    } catch (error) {
      if (error.errCode == 10006) {
        this.topClass.delConnect(this.deviceId, this.typeKey)
      }
      console.error(error)
      logs(`发送出错 基本信息 deviceId：${this.deviceId}, serviceId：${this.serviceId}, writeId：${this.writeId}`)
      logs(error)
    }
  }


}
