<script lang="ts" setup>
import { AES128ECBEncrypt, bufTohex } from '@/utils/aesTools'

definePage({
  style: {
    navigationBarTitleText: '蓝牙连接',
    navigationBarBackgroundColor: '#1488f5',
    navigationBarTextStyle: 'white',
  },
})

const list_item_style = computed(() => {
  return {
    padding: '20rpx 0',
    borderBottom: '2rpx solid #cccccc',
    fontSize: '28rpx',
    color: '#6a6a6a',
  }
})

const list_item_btn_style = computed(() => {
  return {
    height: '35px',
    fontSize: '24rpx',
  }
})

// 配置
const config = reactive({
  TIMEOUT: 5000, // 搜索超时时间
  ISOPEN: false, // 是否打开蓝牙
})
// 蓝牙配置
const bluetoothConfig = reactive({
  deviceId: '', // 设备id
  status: -1, // -1 未初始化 0 连接失败 1 连接成功
  RSSI: 0, // 信号强度
  localName: '', /// / 设备名称
  serviceId: '', // 服务id
  characteristicId: '', // 读特征值id
  writeCharacteristicId: '', // 写入特征值id
  btnIsLoading: false, // 按钮加载中
  isCloseBlue: false, // 是否关闭蓝牙(用于监听蓝牙状态自动连接使用，手动关闭不监听)
  currentInstruct: '', // 当前正在操作的指令
})

//
const notifyRef = ref(null)
const notifyConfig = reactive({
  message: 'asdasdas',
  type: 'primary', // primary，success，warning,error
})

// 指令列表配置
const commandList = reactive({
  // 开锁
  openLock: {
    title: '车锁开',
    key: 'openLock',
    status: 'none', // none,loading,success,fail
    btnText: '执行',
    btnLoadingText: '执行中',
    btnLoading: false,
    msg: '执行车锁开命令：',
  },
})
const codeType = ref<'car' | 'sn'>('car')
const code = ref<string>('')

function handleType() {
  code.value = ''
  codeType.value = codeType.value === 'car' ? 'sn' : 'car'
}

function handleScan() {
  openBluetoothAdapter()
}

// 打开化蓝牙适配器
function openBluetoothAdapter() {
  return new Promise((resolve, reject) => {
    uni.showLoading({
      title: '正在打开蓝牙适配器中。。。',
    })
    uni.openBluetoothAdapter({
      success(res) {
        const { errno } = res
        uni.hideLoading()
        if (errno !== 0) {
          reject(new Error('蓝牙适配器打开失败'))
        }
        config.ISOPEN = true
        resolve(res)
        console.log('蓝牙适配器------>', res)
      },
      fail(err) {
        uni.hideLoading()
        console.error(err)
        reject(new Error('打开蓝牙适配器失败'))
      },
    })
  })
}

// 停止蓝牙适配器
function closeBluetoothAdapter() {
  config.ISOPEN = false
  bluetoothConfig.deviceId = ''
  uni.closeBluetoothAdapter({
    success(res) {
      console.log(res)
    },
    fail(err) {
      console.error(err)
    },
  })
}

// 设置蓝牙设备信息
function setBluetoothDevice(device: any) {
  bluetoothConfig.RSSI = device.RSSI
  bluetoothConfig.localName = device.localName
}

// 停止搜寻附近的蓝牙外围设备
function stopBluetoothDevicesDiscovery() {
  uni.stopBluetoothDevicesDiscovery({
    success(res) {
      console.log(res)
    },
    fail(err) {
      console.error(err)
    },
  })
}

/**
 * 搜索蓝牙设备⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️
 */
async function handleSearch() {
  try {
    bluetoothConfig.btnIsLoading = true
    bluetoothConfig.isCloseBlue = false
    // 判断蓝牙是否打开
    if (!config.ISOPEN) {
      await openBluetoothAdapter()
    }
    const device = await startBluetoothDevicesDiscovery()
    console.log('搜索成功的设备：', device)
    await createBLEConnection()
    await getServiceAndCharacteristicId()
    bluetoothConfig.status = 1
    setBluetoothDevice(device)
    console.log(bluetoothConfig)
    bluetoothConfig.btnIsLoading = false
  }
  catch (error) {
    console.error(error)
    bluetoothConfig.btnIsLoading = false
    closeBluetoothAdapter()
    clearBuletoothConfig()
    uni.showToast({
      title: error.message || '未知错误',
      icon: 'none',
      duration: 1500,
    })
  }
}

// 获取蓝牙设备
async function startBluetoothDevicesDiscovery(targetName = 'ECU-2370171956', timeout = config.TIMEOUT): Promise<any> {
  return new Promise((resolve, reject) => {
    let isCompleted = false // 防止多次 resolve/reject

    const cleanup = () => {
      if (!isCompleted) {
        isCompleted = true
        stopBluetoothDevicesDiscovery()
        uni.hideLoading()
      }
    }

    // 启动搜索
    uni.startBluetoothDevicesDiscovery({
      success: (res) => {
        // 搜索异常
        if (res.errno !== 0) {
          cleanup()
          return reject(new Error('启动蓝牙搜索失败'))
        }

        // 搜索成功
        uni.showLoading({ title: '正在搜索蓝牙设备...' })
        uni.onBluetoothDeviceFound((e: any) => {
          if (isCompleted) {
            return
          };
          const devices = e.devices
          for (let i = 0; i < devices.length; i++) {
            if (devices[i].localName === targetName) {
              bluetoothConfig.deviceId = devices[i].deviceId
              cleanup()
              return resolve(devices[i]) // 找到设备，成功返回
            }
          }
        })

        // 设置超时
        setTimeout(() => {
          if (!isCompleted) {
            cleanup()
            reject(new Error('设备搜索超时'))
          }
        }, timeout)
      },
      fail: (err) => {
        cleanup()
        reject(new Error(`获取蓝牙设备失败: ${err.errMsg || err}`))
      },
    })
  })
}

// 创建低功率蓝牙
function createBLEConnection() {
  return new Promise((resolve, reject) => {
    if (!bluetoothConfig.deviceId) {
      return reject(new Error('蓝牙设备id未知'))
    }

    // 创建低功率蓝牙
    uni.createBLEConnection({
      deviceId: bluetoothConfig.deviceId,
      success: (res: any) => {
        const { errCode } = res
        if (errCode === 0) {
          console.log('创建低功率蓝牙成功', res)
          return resolve(res)
        }
        else {
          bluetoothConfig.status = 0
          reject(new Error(res.errMsg || '创建低功率蓝牙失败'))
        }
      },
      fail: (err) => {
        bluetoothConfig.status = 0
        reject(new Error(`创建低功率蓝牙失败: ${err.errMsg || err}`))
      },
    })
  })
}

/**
 * 寻找匹配的ids
 * @param services 服务列表
 * @param targetSubServiceIds  目标子服务ID
 * @param returnFirst 是否返回第一个匹配项
 */
function findMatchingIds(services: any[] = [], targetSubServiceIds: string[] = [], returnFirst = true) {
  const matches = []

  for (let i = 0; i < services.length; i++) {
    const serviceId = services[i].uuid
    const subServiceId = serviceId.substring(0, 8).toUpperCase() // 统一转大写避免大小写问题

    if (targetSubServiceIds.includes(subServiceId)) {
      matches.push(services[i])
      if (returnFirst) {
        return matches[0] // 返回第一个匹配项
      }
    }
  }

  return returnFirst ? null : matches // 如果没找到，返回 null 或空数组
}

// 获取服务id和特征值id
function getServiceAndCharacteristicId() {
  return new Promise((resolve, reject) => {
    if (!bluetoothConfig.deviceId) {
      reject(new Error('初始化服务id和特征值id失败'))
    }

    // 获取蓝牙设备所有服务(service)。
    uni.getBLEDeviceServices({
      deviceId: bluetoothConfig.deviceId,
      success: (res: any) => {
        const { services } = res

        if (services && services.length > 0) {
          const serviceObj = findMatchingIds(services, ['0000FFF0', '6E400001'])

          if (serviceObj) {
            bluetoothConfig.serviceId = serviceObj.uuid
            console.log('服务id：', bluetoothConfig.serviceId)

            // 获取蓝牙设备某个服务中所有特征值(characteristic)。
            uni.getBLEDeviceCharacteristics({
              deviceId: bluetoothConfig.deviceId,
              serviceId: bluetoothConfig.serviceId,
              success: (rs: any) => {
                const { characteristics } = rs
                if (characteristics && characteristics.length > 0) {
                // 获取读取特征值
                  const characteristicIdObj = findMatchingIds(characteristics, ['0000FFF6', '6E400003'])
                  if (characteristicIdObj) {
                    bluetoothConfig.characteristicId = characteristicIdObj.uuid
                  }

                  // 获取写入特征值
                  const writeCharacteristicIdObj = findMatchingIds(characteristics, ['6E400002'])
                  if (writeCharacteristicIdObj) {
                    bluetoothConfig.writeCharacteristicId = writeCharacteristicIdObj.uuid
                  }
                  console.log('特征值获取', bluetoothConfig.characteristicId, bluetoothConfig.writeCharacteristicId)
                }
                startNotify()
                resolve({
                  serviceId: bluetoothConfig.serviceId,
                  characteristicId: bluetoothConfig.characteristicId,
                  writeCharacteristicId: bluetoothConfig.writeCharacteristicId,
                })
              },
              fail: () => {
                reject(new Error('获取蓝牙设备所有特征值失败------'))
              },
            })
          }
        }
      },
      fail: () => {
        reject(new Error('获取蓝牙设备所有服务失败------'))
      },
    })
  })
}

// 清除蓝牙配置
function clearBuletoothConfig() {
  bluetoothConfig.status = -1
  bluetoothConfig.RSSI = 0
  bluetoothConfig.characteristicId = ''
  bluetoothConfig.serviceId = ''
  bluetoothConfig.deviceId = ''
  bluetoothConfig.localName = ''
  bluetoothConfig.writeCharacteristicId = ''
  bluetoothConfig.isCloseBlue = false
  bluetoothConfig.currentInstruct = ''
}

// 关闭低功率蓝牙
function closeBLEConnection() {
  if (!bluetoothConfig.deviceId)
    return
  uni.closeBLEConnection({
    deviceId: bluetoothConfig.deviceId,
    success: (res: any) => {
      console.log('关闭低功率蓝牙成功', res)
      bluetoothConfig.isCloseBlue = true
      clearBuletoothConfig()
    },
    fail: (err) => {
      clearBuletoothConfig()
      console.log('关闭低功率蓝牙失败', err)
    },
  })
}

// 点击指令
async function handleCommand(value: any, key: string, index: number) {
  const comm = value.key
  bluetoothConfig.currentInstruct = key
  try {
    commandList[key].btnLoading = true
    switch (comm) {
      case 'openLock': { // 开锁
        const buffer = new ArrayBuffer(5)
        const dataView = new DataView(buffer)
        dataView.setUint32(0, 0x67740082)
        dataView.setUint8(4, 0x82)
        await writeBLECharacteristicValueWithBuff(buffer)
        break
      }
    }
    commandList[key].btnLoading = false
  }
  catch (err) {
    commandList[key].btnLoading = false
    console.error(err)
  }
}

function writeBLECharacteristicValueWithBuff(buffer: any) {
  return new Promise((resolve, reject) => {
    if (
      !buffer
      && !bluetoothConfig.writeCharacteristicId
      && !bluetoothConfig.serviceId
      && !bluetoothConfig.deviceId) {
      return
    }
    console.log('writeBLECharacteristicValueWithBuff', buffer)

    uni.writeBLECharacteristicValue({
      deviceId: bluetoothConfig.deviceId,
      serviceId: bluetoothConfig.serviceId,
      characteristicId: bluetoothConfig.writeCharacteristicId,
      value: buffer,
      success(res) {
        resolve(res)
        console.log('writeBLECharacteristicValue success', res.errMsg)
      },
      fail(err: any) {
        reject(new Error(err.errMsg))
      },
      complete(res) {},
    })
  })
}

// 启用低功耗蓝牙设备特征值变化时的 notify 功能
function startNotify() {
  uni.notifyBLECharacteristicValueChange({
    state: true,
    deviceId: bluetoothConfig.deviceId,
    serviceId: bluetoothConfig.serviceId,
    characteristicId: bluetoothConfig.characteristicId,
    success() {
      console.log('notifyBLECharacteristicValueChange success')
      verification()
    },
    fail(err) {
      console.log('notifyBLECharacteristicValueChange fail', err)
    },
  })
}

async function verification(mac: any = undefined, key1: any = undefined, key2: any = undefined) {
  if (mac && key1 && key2) {
    // 数据总长度为21，第一天长度20
    const buffer = new ArrayBuffer(20)
    const dataView = new DataView(buffer)
    dataView.setUint32(0, 0x6774108A)
    const sourceKey1 = mac + key1
    const AESEncrypt = AES128ECBEncrypt(sourceKey1, key2)
    if (AESEncrypt.length !== 32) {
      return
    }
    for (let i = 0; i < 4; i++) {
      const subStr = AESEncrypt.substring(i * 8, i * 8 + 8, 16)
      dataView.setUint32(i * 4 + 4, Number.parseInt(subStr, 16)) // 4字节01523947(16进制)-->>10进制数字-->放入dateView
    }
    let i
    let bcc // 17为数据长度16+1
    for (i = 0; i < 17; i++) {
      bcc ^= dataView.getInt8(i + 3)
    }
    const buffer2 = new ArrayBuffer(1)
    const dataView2 = new DataView(buffer2)
    dataView2.setUint8(0, bcc)
    console.log('验证---------------->', bufTohex(buffer))
    writeBLECharacteristicValueWithBuff(buffer)
    setTimeout(() => {
      writeBLECharacteristicValueWithBuff(buffer2)
    }, 300)
  }
  else {
    const buffer = new ArrayBuffer(5)
    const dataView = new DataView(buffer)
    dataView.setUint32(0, 0x6774008A)
    dataView.setUint8(4, 0x8A)
    await writeBLECharacteristicValueWithBuff(buffer)
  }
}

let verificationTimes = 0
function distributeCommandsWithDataStr(hex: string) {
  const cmd = hex.substring(6, 8)
  const code = hex.substring(8, 10)
  let errCode: any = code
  const desDic: any = {}
  let des = ''

  // 应答码定义
  if (code === '00') {
    des = '成功'
    errCode = 0
  }
  else if (code === 'ff') {
    // -1
    des = '锁已打开'
    errCode = -1
  }
  else if (code === 'fe') {
    // -2
    des = '电量不足'
    errCode = -2
  }
  else if (code === 'fd') {
    // -3
    des = '加密验证失败'
    errCode = -3
  }
  else if (code === 'fc') {
    // -4
    des = '内存空间不足'
    errCode = -4
  }
  else if (code === 'fb') {
    // -5
    des = '格式错误'
    errCode = -5
  }
  else if (code === 'fa') {
    // -6
    des = '没有验证或验证失败'
    errCode = -6
    desDic.mac = hex.substring(10, 22)
    desDic.key = hex.substring(22, 30)
  }
  else if (code === 'f9') {
    // -7
    des = 'flash写入失败'
    errCode = -7
  }
  else if (code === 'f8') {
    // -8
    des = '数据空'
    errCode = -8
  }
  else if (code === 'f7') {
    // -9
    des = '操作失败'
    errCode = -9
  }
  else if (code === 'f6') {
    // -10
    des = '运输模式下无法执行该指令'
    errCode = -10
  }
  else if (code === 'f5') {
    // -11
    des = '锁车失败，车辆未停止'
    errCode = -11
  }
  else if (code === 'f4') {
    // -12
    des = '未检测到道钉信息'
    errCode = -12
  }
  else if (Number.parseInt(code, 16) === 149) {
    //
    des = '摄像头正在工作中'
    errCode = Number.parseInt(code, 16)
  }
  else if (Number.parseInt(code, 16) === 150) {
    //
    des = '摄像头离线'
    errCode = Number.parseInt(code, 16)
  }
  else if (Number.parseInt(code, 16) === 151) {
    //
    des = '车辆不在使用中（临时停车或是还车中）无法使用摄像头还车'
    errCode = Number.parseInt(code, 16)
  }
  else if (Number.parseInt(code, 16) === 152) {
    //
    des = '执行命令超时'
    errCode = Number.parseInt(code, 16)
  }
  else if (Number.parseInt(code, 16) === 153) {
    //
    des = '摄像头执行失败'
    errCode = Number.parseInt(code, 16)
  }
  else if (Number.parseInt(code, 16) === 154) {
    //
    des = '不在站点中或没有垂直停车'
    errCode = Number.parseInt(code, 16)
  }
  else {
    des = `未知错误码${code}`
    errCode = code
  }

  console.log('distributeCommandsWithDataStr', hex)
  desDic.errCode = errCode
  desDic.des = des

  // 提示显示
  if (bluetoothConfig.currentInstruct) {
    const message = commandList[bluetoothConfig.currentInstruct].msg + desDic.des
    notifyRef.value.show({
      type: 'success',
      message,
      safeAreaInsetTop: true,
    })
  }

  if (cmd === '4a') {
    // 验证
    if (verificationTimes >= 1) {
      verificationTimes = 0

      if (errCode === -6) {
        verificationTimes = 1
        verification(desDic.mac, desDic.key, '6666660000888888')
        return
      }
    }
    else {
      verificationTimes += 1
    }
    if (errCode === -6) {
      verification(desDic.mac, desDic.key, '6666660000888888')
    }
  }
}

// 监听蓝牙连接状态改变
uni.onBLEConnectionStateChange(async (res) => {
  console.log('蓝牙连接状态改变', res)
  try {
    const { connected } = res
    if (!connected && !bluetoothConfig.isCloseBlue) {
      bluetoothConfig.status = 0

      await createBLEConnection()
      await getServiceAndCharacteristicId()
      bluetoothConfig.status = 1

    //   if (reconnectNum < 3) {
    //     await createBLEConnection()
    //     reconnectNum += 1
    //   }
    //   else {
    //     closeBLEConnection()
    //   }
    // }
    }
  }
  catch (err) {
    console.log('蓝牙连接状态改变失败', err)
  }
})

// 监听低功耗蓝牙设备的特征值变化事件
uni.onBLECharacteristicValueChange((res) => {
  console.log('onBLECharacteristicValueChange-----------》', res)
  const hex = bufTohex(res.value)
  if (hex.length >= 10) {
    const header = hex.substring(0, 4)
    if (header === '6774') {
      const contentL1 = hex.substring(4, 6)
      const contentL = Number.parseInt(contentL1, 16)
      if ((contentL + 5) * 2 === hex.length) {
        distributeCommandsWithDataStr(hex)
      }
      else if ((contentL + 5) * 2 > hex.length) {
        // self.responseStr = hex
      }
    }
  }
})

onBeforeUnmount(() => {
  if (config.ISOPEN) {
    closeBluetoothAdapter()
  }
  closeBLEConnection()
  clearBuletoothConfig()
})
</script>

<template>
  <z-paging
    ref="paging"
    bg-color="#f3f3f3"
  >
    <view class="container">
      <!-- 编号输入框 -->
      <view class="card_bar">
        <!-- 车辆编号 -->
        <view class="card_item card_border">
          <view class="card_item_title">
            <uv-button
              plain style="margin-right: 25rpx;"
              @click="handleType"
            >
              <uv-icon
                name="jiantou_shangxiaqiehuan"
                custom-prefix="custom-icon"
                size="20"
              />
              <text>{{ codeType === 'car' ? '车辆编号' : "中控SN" }}</text>
            </uv-button>
          </view>
          <view class="card_item_value">
            <uv-input
              v-model="code"
              placeholder="请输入或扫码"
            >
              <template #suffix>
                <uv-icon name="scan" size="22" @click="handleScan" />
              </template>
            </uv-input>
          </view>
        </view>
        <!-- 设备信息 -->
        <view class="card_item">
          <view class="card_item_title">
            设备编号：
          </view>
          <view class="card_item_value">
            {{ bluetoothConfig.localName || '--' }}
          </view>
        </view>
        <view class="device_bar">
          <text
            :style="{
              color: bluetoothConfig.status === 0 ? '#f00' : bluetoothConfig.status === 1 ? '#04b604' : '',
            }"
          >
            状态：{{ bluetoothConfig.status === -1 ? '未连接' : bluetoothConfig.status === 0 ? '连接失败' : '连接成功' }}
          </text>
          <text>信号强度：{{ bluetoothConfig.RSSI || 0 }}</text>
        </view>
      </view>

      <!-- 配置信息栏 -->
      <view class="card_bar u-m-t-30">
        <uv-list>
          <uv-list-item
            v-for="(value, key, index) in commandList"
            :key="key"
            :custom-style="list_item_style"
          >
            <view class="list-item">
              <view class="text_bar">
                <view>{{ value.title }} </view>
              </view>
              <view class="btn_bar">
                <uv-button
                  type="primary"
                  :loading="value.btnLoading"
                  :loading-text="value.btnLoadingText"
                  :text="value.btnText"
                  :disabled="bluetoothConfig.status !== 1"
                  :custom-style="list_item_btn_style"
                  @click="handleCommand(value, key, index)"
                />
              </view>
            </view>
          </uv-list-item>
        </uv-list>
      </view>
    </view>

    <template #bottom>
      <view class="bottom-button-zaping">
        <uv-button
          v-if="bluetoothConfig.status === -1"
          type="primary"
          text="连接设备"
          :loading="bluetoothConfig.btnIsLoading"
          loading-text="正在连接中"
          @click="handleSearch"
        />
        <uv-button
          v-if="bluetoothConfig.status === 1"
          type="error"
          text="断开连接"
          @click="closeBLEConnection"
        />
        <uv-button
          v-if="bluetoothConfig.status === 0"
          type="primary"
          text="连接设备"
          :loading="true"
          loading-text="正在重连"
        />
      </view>
    </template>

    <uv-notify ref="notifyRef" />
  </z-paging>
</template>

<style lang="scss" scoped>
.container {
  width: calc(100% - 40rpx);
  padding: 10rpx 20rpx;

  .card_bar {
    width: calc(100% - 40rpx);
    background-color: #fff;
    border-radius: 10rpx;
    box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
    padding: 20rpx;

    .card_item {
      padding: 20rpx 0;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .card_item_title {
        width: 100rpx;
        font-size: 30rpx;
        color: $font-gray;
        flex: 1;
      }

      .card_item_value {
        flex: 2;
      }
    }
  }
  .device_bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 28rpx;
    color: $font-gray;
  }
}
.card_border {
  border-bottom: 2rpx solid #d5d0d0;
}

.list-item {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;

  .text_bar {
    font-size: 28rpx;
    display: flex;
    align-items: center;

    .result {
      margin-left: 30rpx;
    }
  }
}
</style>
