import errToString from "./error";
import {logs, promisify} from '../util'
import {ab2hex} from "@/utils/ble/hex";

function _onBluetoothAdapterStateChange(callback) {
  /* #ifndef H5 */
  uni.onBluetoothAdapterStateChange(res => {
    // 处理蓝牙开启与关闭问题
    callback(res)
  })
  /* #endif */
}

function _onBLEConnectionStateChange(callback) {
  /* #ifndef H5 */
  uni.onBLEConnectionStateChange(res => {
    // 该方法回调中可以用于处理连接意外断开等异常情况
    callback(res)
  })
  /* #endif */
}

function _onBLECharacteristicValueChange(callback) {
  /* #ifndef H5 */
  uni.onBLECharacteristicValueChange(res => {
    res.str = ab2hex(res.value)
    callback(res)
  })
  /* #endif */
}

function _openAdapter() {
  logs(`准备初始化蓝牙适配器...`);
  return uni.openBluetoothAdapter().then(
    (res) => {
      logs(`✔ 适配器初始化成功！`);
      return res;
    },
    (err) => {
      throw `初始化失败！${errToString(err)}`
    }
  );
}

/**
 * @param {Array<string>} services
 * @param { Int } interval
 */
function _startSearch(data = {}) {
  logs(`准备搜寻附近的蓝牙外围设备...`);
  /* #ifndef H5 */
  return promisify(uni.startBluetoothDevicesDiscovery, Object.assign({
    interval: 10
  }, data)).then(
    (res) => {
      logs(`✔ 搜索成功!`);
      return res
    },
    (err) => {
      throw `搜索蓝牙失败！${errToString(err)}`
    }
  );
  /* #endif */
}

/**
 * 获取已发现的蓝牙设备
 * @returns {Promise<[null, undefined] | [(string|string), Object]>}
 * @private
 */
function _getBluetoothDevices() {
  return promisify(uni.getBluetoothDevices).then(
    ({devices}) => {
      logs(`✔ 获取已发现的蓝牙设备成功!`);
      let list = devices.filter(function (obj) {
        return obj.advertisData; //这里过滤自己想要的设备
      })
      logs('已发现的蓝牙设备列表');
      return list
    },
    (err) => {
      throw `获取已发现的蓝牙设备失败！${errToString(err)}`
    }
  );
}

/**
 * @param {Array} devices 查找到设备数组
 * @param {int} count 计数器-嗅探2次
 */
function _onBluetoothFound(maxCount = 3) {
  let devices = []
  let count = 0
  /* #ifdef H5 */
  return Promise.resolve(devices)
  /* #endif */
  return new Promise((resolve, reject) => {
    uni.onBluetoothDeviceFound(res => {
      devices.push(...res.devices)
      count++
      if (count > maxCount) {
        resolve(devices)
      }
      logs(`已嗅探蓝牙设备数：${devices.length}...`)
    }, err => {
      reject(err)
    })
  })
}

/**
 * 停止蓝牙搜索
 * @returns {PromiseLike<[null, any] | [(string|string), null]> | Promise<[null, any] | [(string|string), null]>}
 * @private
 */
function _stopSearchBluetooth() {
  logs(`停止查找新设备...`);
  /* #ifdef H5 */
  throw `停止查询失败！H5不能操作`
  /* #endif */
  return uni.stopBluetoothDevicesDiscovery().then(
    (res) => {
      logs(`✔ 停止查找设备成功！`);
      return res
    },
    (err) => {
      throw `停止查询失败！${errToString(err)}`
    }
  );
}

/**
 * 连接设备
 * @param deviceId
 * @returns {Promise<[null, unknown] | [null, any] | [(string|string), null]>}
 * @private
 */
function _connectBlue(deviceId) {
  logs(`准备连接设备...`);
  /* #ifndef H5 */
  return promisify(uni.createBLEConnection, {
    deviceId,
  }).then(
    (res) => {
      logs(`✔ 连接蓝牙成功！`);
      return true
    },
    (err) => {
      if (err.errCode == 10010) {
        logs(`✔ 连接蓝牙成功！`);
        return true
      } else {
        throw `连接蓝牙失败！ ${errToString(err)}`
      }
    }
  );
  /* #endif */
}

/**
 * 关闭设备蓝牙
 * @param deviceId
 * @returns {Promise<[null, unknown] | [(string|string), null]>}
 * @private
 */
function _closeBLEConnection(deviceId) {
  logs(`断开蓝牙连接...`)
  /* #ifndef H5 */
  return promisify(uni.closeBLEConnection, {
    deviceId,
  }).then(
    (res) => {
      logs(`✔ 断开蓝牙成功！`);
      return true
    },
    (err) => {
      throw `断开蓝牙连接失败！ ${errToString(err)}`
    }
  );
  /* #endif */
}

/**
 * 关闭蓝牙
 * @returns {Promise<[null, unknown] | [(string|string), null]>}
 * @private
 */
function _closeBLEAdapter() {
  logs(`释放蓝牙适配器...`)
  return promisify(uni.closeBluetoothAdapter).then(
    (res) => {
      logs(`✔ 释放适配器成功！`)
      return res
    },
    (err) => {
      throw `释放适配器失败！ ${errToString(err)}`
    }
  );
}

/**
 * 获取设备服务列表
 * @param deviceId
 * @returns {Promise<[null, unknown] | [(string|string), null]>}
 * @private
 */
function _getBLEServices(deviceId) {
  logs(`获取蓝牙设备所有服务...`)
  return promisify(uni.getBLEDeviceServices, {
    deviceId
  }).then(res => {
    logs(`✔ 获取service成功！`)
    return res
  }, err => {
    throw `获取service失败！ ${errToString(err)}`
  })
}

/**
 * 获取服务通道
 * @param deviceId
 * @param serviceId
 * @returns {Promise<[null, unknown] | [(string|string), null]>}
 * @private
 */
function _getCharacteristics(deviceId, serviceId) {
  logs(`开始获取特征值...`);
  return promisify(uni.getBLEDeviceCharacteristics, {
    deviceId,
    serviceId,
  }).then(
    (res) => {
      logs(`✔ 获取特征值成功！`);
      return res
    },
    (err) => {
      throw `获取特征值失败！ ${errToString(err)}`
    }
  );
}

// 订阅特征值
function _notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) {
  return promisify(uni.notifyBLECharacteristicValueChange, {
    deviceId,
    serviceId,
    characteristicId,
    state: true
  }).then(res => {
    logs(`✔ 订阅notify成功！`)
    return true
  }, err => {
    throw `订阅notify失败！ ${errToString(err)}`
  })
}


function _writeBLECharacteristicValue(deviceId, serviceId, characteristicId, buffer) {
  return promisify(uni.writeBLECharacteristicValue, {
    deviceId,
    serviceId,
    characteristicId,
    value: buffer,
  }).then(res => {
    return res
  }, err => {
    throw {
      code: err.errCode,
      msg: `写入数据失败！ ${errToString(err)}`
    }
  })
}

export {
  _onBLEConnectionStateChange,
  _onBluetoothAdapterStateChange,
  _openAdapter,
  _getCharacteristics,
  _connectBlue,
  _getBLEServices,
  _closeBLEConnection,
  _closeBLEAdapter,
  _stopSearchBluetooth,
  _getBluetoothDevices,
  _notifyBLECharacteristicValueChange,
  _onBluetoothFound,
  _startSearch,
  _writeBLECharacteristicValue,
  _onBLECharacteristicValueChange,
};
