// 全局状态变量
let tempTimer = 0;
let client = null;
let util = null;
let mDeviceEvent = null;
let crypto = null;
let md5 = null;
let aesjs = null;
const timeOut = 20; // 超时时间
let timeId = "";
let sequenceControl = 0;
// let sequenceNumber = -1; // 此变量在代码中未被使用，可以移除

// _self 对象用于维护单个连接会话的状态
let _self = {
  data: {
    deviceId: null,
    isConnected: false,
    failure: false,
    value: 0,
    desc: "请耐心等待...",
    isChecksum: true,
    isEncrypt: true,
    flagEnd: false,
    defaultData: 1,
    ssidType: 2,
    passwordType: 3,
    meshIdType: 3,
    ssid: "",
    password: "",
    meshId: "",
    uuid: "",
    serviceId: "",
    processList: [],
    result: [],
    service_uuid: "0000FFFF-0000-1000-8000-00805F9B34FB",
    characteristic_write_uuid: "0000FF01-0000-1000-8000-00805F9B34FB",
    characteristic_read_uuid: "0000FF02-0000-1000-8000-00805F9B34FB",
    customData: null,
    md5Key: 0,
  }
};

// =================================================================
//                      辅助/工具函数 (已优化)
// =================================================================

/**
 * 将 ArrayBuffer 转换为十六进制字符串
 * @param {ArrayBuffer} buffer
 * @returns {string}
 */
function buf2hex(buffer) {
  return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}

/**
 * [优化] 将 ArrayBuffer (字节数组) 转换为字符串。
 * 使用 TextDecoder API，性能更高且能正确处理 UTF-8 编码。
 * @param {ArrayBuffer} buffer
 * @returns {string}
 */
function buf2string(buffer) {
  try {
    const dataView = new DataView(buffer);
    // 微信小程序环境支持 TextDecoder
    const decoder = new TextDecoder('utf-8');
    return decoder.decode(dataView);
  } catch (e) {
    // 降级处理，以防极旧环境不支持
    const arr = Array.prototype.map.call(new Uint8Array(buffer), x => x);
    let str = '';
    for (let i = 0; i < arr.length; i++) {
      str += String.fromCharCode(arr[i]);
    }
    return decodeURIComponent(escape(str));
  }
}


/**
 * [优化] 将字符串转换为 UTF-8 编码的字节数组。
 * 使用 TextEncoder API，性能远超手动循环，且编码更标准。
 * @param {string} str
 * @returns {number[]}
 */
function stringToUtf8Bytes(str) {
  try {
    // 微信小程序环境支持 TextEncoder
    const encoder = new TextEncoder();
    return Array.from(encoder.encode(str));
  } catch (e) {
    // 降级处理
    return unescape(encodeURIComponent(str)).split("").map(val => val.charCodeAt());
  }
}

/**
 * [优化] 判断并处理返回的数据帧，提取负载数据。
 * 简化了原有的 if/else 重复逻辑。
 * @param {string[]} fragNum - 帧控制字段的二进制数组
 * @param {number[]} list - 原始数据包
 * @param {any} md5Key - MD5密钥
 * @returns {number[]} - 提取出的负载数据
 */
function parsePayload(fragNum, list, md5Key) {
  let payload = list;
  // 步骤1: 如果有校验和，则移除末尾的校验位
  if (fragNum[6] == "1") {
    payload = payload.slice(0, payload.length - 2);
  }

  // 步骤2: 根据是否加密进行解密 (当前代码中解密逻辑未实现，仅预留位置)
  if (fragNum[7] == "1") {
    // 返回数据已加密
    // let iv = this.generateAESIV(parseInt(payload[2], 16));
    // 在此处添加解密逻辑...
  }

  // 步骤3: 根据是否分包，移除帧头，提取有效数据
  if (fragNum[3] == "0") { // 未分包
    _self.data.flagEnd = true;
    return payload.slice(4);
  } else { // 分包
    _self.data.flagEnd = false;
    return payload.slice(6);
  }
}


// =================================================================
//                      BLE 核心写入函数
// =================================================================

/**
 * 发送安全协商数据 (P, G, K)
 * @param {string} deviceId
 * @param {string} serviceId
 * @param {string} characteristicId
 * @param {object} client - DH 客户端实例
 * @param {number[]} kBytes - 公钥
 * @param {number[]} pBytes - P
 * @param {number[]} gBytes - G
 * @param {number[]|null} data - 分包后的剩余数据
 */
function getSecret(deviceId, serviceId, characteristicId, client, kBytes, pBytes, gBytes, data) {
  let obj = {};
  let frameControl = 0;
  sequenceControl = parseInt(sequenceControl) + 1;

  if (!util._isEmpty(data)) {
    obj = util.isSubcontractor(data, true, sequenceControl);
    frameControl = util.getFrameCTRLValue(false, true, util.DIRECTION_OUTPUT, false, obj.flag);
  } else {
    let payload = [];
    payload.push(util.NEG_SET_SEC_ALL_DATA);
    
    const pLength = pBytes.length;
    payload.push((pLength >> 8) & 0xff, pLength & 0xff, ...pBytes);

    const gLength = gBytes.length;
    payload.push((gLength >> 8) & 0xff, gLength & 0xff, ...gBytes);

    const kLength = kBytes.length;
    payload.push((kLength >> 8) & 0xff, kLength & 0xff, ...kBytes);

    obj = util.isSubcontractor(payload, true, sequenceControl);
    frameControl = util.getFrameCTRLValue(false, true, util.DIRECTION_OUTPUT, false, obj.flag);
  }

  const value = util.writeData(util.PACKAGE_VALUE, util.SUBTYPE_NEG, frameControl, sequenceControl, obj.len, obj.lenData);
  const typedArray = new Uint8Array(value);

  wx.writeBLECharacteristicValue({
    deviceId: deviceId,
    serviceId: serviceId,
    characteristicId: characteristicId,
    value: typedArray.buffer,
    success: function (res) {
      if (obj.flag) { // 如果有剩余数据，则继续发送
        getSecret(deviceId, serviceId, characteristicId, client, kBytes, pBytes, gBytes, obj.laveData);
      }
    },
    fail: function (res) {
      console.error("getSecret failed:", res, { deviceId, serviceId, characteristicId });
    }
  });
}

/**
 * [新增] 通用的数据包发送函数，用于取代原先多个重复的 writeXXX 函数
 * @param {number} subType - 包的子类型
 * @param {number[]} dataPayload - 要发送的原始数据负载
 * @param {function} onSuccess - 发送成功（且无分包）后的回调函数
 */
function sendBlufiDataPacket(subType, dataPayload, onSuccess) {
  const deviceId = _self.data.deviceId;
  const serviceId = _self.data.service_uuid;
  const characteristicId = _self.data.characteristic_write_uuid;

  function writePacket(remainingData) {
    sequenceControl = parseInt(sequenceControl) + 1;
    
    // 检查是否需要分包
    const obj = util.isSubcontractor(remainingData, _self.data.isChecksum, sequenceControl, _self.data.isEncrypt);
    const frameControl = util.getFrameCTRLValue(_self.data.isEncrypt, _self.data.isChecksum, util.DIRECTION_OUTPUT, false, obj.flag);
    
    // 加密数据
    const encryptedData = util.encrypt(aesjs, _self.data.md5Key, sequenceControl, obj.lenData, true);
    
    // 组装最终数据包
    const value = util.writeData(util.PACKAGE_VALUE, subType, frameControl, sequenceControl, obj.len, encryptedData);
    const typedArray = new Uint8Array(value);

    wx.writeBLECharacteristicValue({
      deviceId: deviceId,
      serviceId: serviceId,
      characteristicId: characteristicId,
      value: typedArray.buffer,
      success: function (res) {
        if (obj.flag) {
          // 如果有分包，继续发送剩余数据
          writePacket(obj.laveData);
        } else if (onSuccess) {
          // 发送完成，执行成功回调
          onSuccess();
        }
      },
      fail: function (res) {
        console.error(`sendBlufiDataPacket failed for subType ${subType}:`, res);
      }
    });
  }

  // 启动第一次写入
  writePacket(dataPayload);
}


function writeDeviceRouterInfoStart() {
  const payload = [_self.data.defaultData];
  const onSuccess = () => writeRouterSsid();
  // 注意：此处的 subType 需要根据你的 util 库定义来确定
  sendBlufiDataPacket(util.SUBTYPE_WIFI_MODEl, payload, onSuccess);
}

function writeRouterSsid() {
  const ssidData = stringToUtf8Bytes(_self.data.ssid);
  const onSuccess = () => writeDevicePwd();
  sendBlufiDataPacket(util.SUBTYPE_SET_SSID, ssidData, onSuccess);
}

function writeDevicePwd() {
  const pwdData = stringToUtf8Bytes(_self.data.password);
  const onSuccess = () => writeDeviceEnd();
  sendBlufiDataPacket(util.SUBTYPE_SET_PWD, pwdData, onSuccess);
}

function writeCutomsData() {
    const customDataBytes = stringToUtf8Bytes(_self.data.customData);
    // 自定义数据发送后通常没有下一步，所以 onSuccess 为 null
    sendBlufiDataPacket(util.SUBTYPE_CUSTOM_DATA, customDataBytes, null);
}

/**
 * 发送结束指令
 */
function writeDeviceEnd() {
  sequenceControl = parseInt(sequenceControl) + 1;
  const frameControl = util.getFrameCTRLValue(_self.data.isEncrypt, false, util.DIRECTION_OUTPUT, false, false);
  const value = util.writeData(_self.data.PACKAGE_CONTROL_VALUE, util.SUBTYPE_END, frameControl, sequenceControl, 0, null);
  const typedArray = new Uint8Array(value);

  wx.writeBLECharacteristicValue({
    deviceId: _self.data.deviceId,
    serviceId: _self.data.service_uuid,
    characteristicId: _self.data.characteristic_write_uuid,
    value: typedArray.buffer,
    success: function (res) {},
    fail: function (res) {}
  });
}

/**
 * 发送获取附近Wi-Fi列表的指令
 */
function writeGetNearRouterSsid() {
    const deviceId = _self.data.deviceId;
    const serviceId = _self.data.service_uuid;
    const characteristicId = _self.data.characteristic_write_uuid;
    sequenceControl = parseInt(sequenceControl) + 1;
    const frameControl = util.getFrameCTRLValue(_self.data.isEncrypt, false, util.DIRECTION_OUTPUT, false, false);
    const value = util.writeData(util.PACKAGE_CONTROL_VALUE, util.SUBTYPE_WIFI_NEG, frameControl, sequenceControl, 0, null);
    const typedArray = new Uint8Array(value);

    wx.writeBLECharacteristicValue({
        deviceId: deviceId,
        serviceId: serviceId,
        characteristicId: characteristicId,
        value: typedArray.buffer,
        success: function (res) {},
        fail: function (res) {}
    });
}


// =================================================================
//                      事件监听与主逻辑
// =================================================================

function init() {
  // 加载依赖
  mDeviceEvent = require('./xBlufi.js');
  util = require('@/utils/blufi/util.js');
  crypto = require('@/utils/blufi/crypto/crypto-dh.js');
  md5 = require('@/utils/blufi/crypto/md5.min.js');
  aesjs = require('@/utils/blufi/crypto/aes.js');

  // 监听蓝牙连接状态变化
  wx.onBLEConnectionStateChange(function (res) {
    const obj = {
      'type': mDeviceEvent.XBLUFI_TYPE.TYPE_STATUS_CONNECTED,
      'result': res.connected,
      'data': res
    };
    mDeviceEvent.notifyDeviceMsgEvent(obj);
  });

  // 监听开始扫描蓝牙设备事件
  mDeviceEvent.listenStartDiscoverBle(true, function (options) {
    if (options.isStart) {
      wx.closeBluetoothAdapter({
        complete: function (res) {
          wx.openBluetoothAdapter({
            success: function (res) {
              wx.startBluetoothDevicesDiscovery({
                allowDuplicatesKey: true,
                success: function (res) {
                  const devicesList = [];
                  const foundDevices = new Set(); // 使用 Set 来快速去重

                  mDeviceEvent.notifyDeviceMsgEvent({
                    'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START,
                    'result': true,
                    'data': res
                  });

                  wx.onBluetoothDeviceFound(function (deviceRes) {
                    const device = deviceRes.devices[0];
                    if (device && device.deviceId && !foundDevices.has(device.deviceId)) {
                      foundDevices.add(device.deviceId);
                      devicesList.push({
                        ...device,
                        advertisData: device.advertisData ? buf2hex(device.advertisData) : ''
                      });

                      mDeviceEvent.notifyDeviceMsgEvent({
                        'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS,
                        'result': true,
                        'data': [...devicesList] // 发送列表的副本
                      });
                    }
                  });
                },
                fail: function (res) {
                  mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START, 'result': false, 'data': res });
                }
              });
            },
            fail: function (res) {
              mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START, 'result': false, 'data': res });
            }
          });
        }
      });
    } else {
      wx.stopBluetoothDevicesDiscovery({
        success: function (res) {
          mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_STOP, 'result': true, 'data': res });
        },
        fail: function (res) {
          mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_STOP, 'result': false, 'data': res });
        }
      });
    }
  });

  // 监听连接/断开蓝牙设备事件 (按要求，此函数未修改)
  mDeviceEvent.listenConnectBle(true, function (options) {
    //console.log("我要连接？", (options.isStart))

    if (options.isStart)
      wx.createBLEConnection({
        deviceId: options.deviceId,
        success: function (res) {
          wx.setBLEMTU({
            deviceId: options.deviceId,
            mtu: 128
          })
          _self.data.deviceId = options.deviceId
          mDeviceEvent.notifyDeviceMsgEvent({
            'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECTED,
            'result': true,
            'data': {
              deviceId: options.deviceId,
              name: options.name
            },
          });
        },
        fail: function (res) {
          _self.data.deviceId = null
          mDeviceEvent.notifyDeviceMsgEvent({
            'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECTED,
            'result': false,
            'data': res,
          });
        }
      });
    else wx.closeBLEConnection({
      deviceId: options.deviceId,
      success: function (res) {
        console.log('断开成功')
        _self.data.deviceId = null
        mDeviceEvent.notifyDeviceMsgEvent({
          'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CLOSE_CONNECTED,
          'result': true,
          'data': {
            deviceId: options.deviceId,
            name: options.name
          }
        });
      },
      fail: function (res) {
        _self.data.deviceId = null
        mDeviceEvent.notifyDeviceMsgEvent({
          'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CLOSE_CONNECTED,
          'result': false,
          'data': res,
        });
      }
    })
  });

  // 监听初始化ESP32(BluFi流程)事件
  mDeviceEvent.listenInitBleEsp32(true, function (options) {
    // 重置状态
    sequenceControl = 0;
    _self.data.result = [];
    _self.data.deviceId = options.deviceId;
    
    wx.getBLEDeviceServices({
      deviceId: options.deviceId,
      success: function (res) {
        const service = res.services.find(s => s.uuid === _self.data.service_uuid);
        if (!service) {
          throw new Error("Blufi service not found");
        }
        
        const serviceId = service.uuid;
        wx.getBLEDeviceCharacteristics({
          deviceId: options.deviceId,
          serviceId: serviceId,
          success: function (charRes) {
            const writeChar = charRes.characteristics.find(c => c.uuid === _self.data.characteristic_write_uuid);
            const readChar = charRes.characteristics.find(c => c.uuid === _self.data.characteristic_read_uuid);
            if (!writeChar || !readChar) {
              throw new Error("Blufi characteristics not found");
            }
            
            _self.data.serviceId = serviceId;
            _self.data.uuid = writeChar.uuid;

            wx.notifyBLECharacteristicValueChange({
              state: true,
              deviceId: options.deviceId,
              serviceId: serviceId,
              characteristicId: readChar.uuid,
              success: function (notifyRes) {
                // 启用通知成功，开始安全协商
                client = util.blueDH(util.DH_P, util.DH_G, crypto);
                const kBytes = util.uint8ArrayToArray(client.getPublicKey());
                const pBytes = util.hexByInt(util.DH_P);
                const gBytes = util.hexByInt(util.DH_G);

                const pgkLength = pBytes.length + gBytes.length + kBytes.length + 6;
                const data = [
                  util.NEG_SET_SEC_TOTAL_LEN,
                  (pgkLength >> 8) & 0xff,
                  pgkLength & 0xff
                ];
                
                const frameControl = util.getFrameCTRLValue(false, false, util.DIRECTION_OUTPUT, false, false);
                const value = util.writeData(util.PACKAGE_VALUE, util.SUBTYPE_NEG, frameControl, sequenceControl, data.length, data);
                const typedArray = new Uint8Array(value);

                wx.writeBLECharacteristicValue({
                  deviceId: options.deviceId,
                  serviceId: serviceId,
                  characteristicId: writeChar.uuid,
                  value: typedArray.buffer,
                  success: function (writeRes) {
                    getSecret(options.deviceId, serviceId, writeChar.uuid, client, kBytes, pBytes, gBytes, null);
                  },
                  fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
                });

                // 监听从设备返回的数据
                wx.onBLECharacteristicValueChange(function (changeRes) {
                  const list2 = (util.ab2hex(changeRes.value));
                  if (list2.length < 4) { return; }

                  const val = parseInt(list2[0], 16);
                  const type = val & 3;
                  const subType = val >> 2;
                  
                  // 使用优化后的 payload 解析函数
                  const fragNum = util.hexToBinArray(list2[1]);
                  const payload = parsePayload(fragNum, list2, _self.data.md5Key);

                  _self.data.result = _self.data.result.concat(payload);

                  if (_self.data.flagEnd) {
                    const resultData = [..._self.data.result];
                    _self.data.result = []; // 清空缓存
                    
                    if (type == 1) { // Type: Data
                        console.log("Receive data, subType: ", subType);
                        switch (subType) {
                            case util.SUBTYPE_NEGOTIATION_NEG: // 安全协商响应
                                const arr = util.hexByInt(resultData.join(""));
                                const clientSecret = client.computeSecret(new Uint8Array(arr));
                                _self.data.md5Key = md5.array(clientSecret);
                                mDeviceEvent.notifyDeviceMsgEvent({
                                    'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT,
                                    'result': true,
                                    'data': { deviceId: options.deviceId, serviceId, characteristicId: writeChar.uuid }
                                });
                                break;
                            case 15: // Wi-Fi连接状态报告
                                const stationStatus = String.fromCharCode(...resultData.map(hex => parseInt(hex, 16)));
                                mDeviceEvent.notifyDeviceMsgEvent({
                                    'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECT_ROUTER_RESULT,
                                    'result': resultData.length > 3,
                                    'data': { 'progress': 100, 'status': stationStatus }
                                });
                                break;
                            case 17: // 附近Wi-Fi列表
                                getList(resultData);
                                break;
                            case 19: // 自定义数据
                                const customDataStr = String.fromCharCode(...resultData.map(hex => parseInt(hex, 16)));
                                mDeviceEvent.notifyDeviceMsgEvent({
                                    'type': mDeviceEvent.XBLUFI_TYPE.TYPE_RECIEVE_CUSTON_DATA,
                                    'result': true,
                                    'data': customDataStr
                                });
                                break;
                            default:
                                console.log("Unhandled data subType:", subType);
                                break;
                        }
                    } else {
                        console.error("Received an error type frame:", type);
                    }
                  }
                });

              },
              fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
            });
          },
          fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
        });
      },
      fail: (err) => mDeviceEvent.notifyDeviceMsgEvent({ 'type': mDeviceEvent.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT, 'result': false, 'data': err })
    });
  });

  // 监听发送SSID和密码事件
  mDeviceEvent.listenSendRouterSsidAndPassword(true, function (options) {
    _self.data.password = options.password;
    _self.data.ssid = options.ssid;
    writeDeviceRouterInfoStart();
  });

  // 监听发送自定义数据事件
  mDeviceEvent.listenSendCustomData(true, function (options) {
    _self.data.customData = options.customData;
    writeCutomsData();
  });
  
  // 监听发送获取附近Wi-Fi指令事件
  mDeviceEvent.listenSendGetNearRouterSsid(true, function(options) {
      writeGetNearRouterSsid();
  });
}

/**
 * [优化] 处理Wi-Fi列表数据
 * 使用循环和索引替代递归和splice，性能更高。
 * @param {number[]} arr - 包含所有Wi-Fi信息的字节数组
 */
function getList(arr) {
  let currentIndex = 0;
  while (currentIndex < arr.length) {
    const len = parseInt(arr[currentIndex], 16);
    if (len <= 0) {
      // 长度异常，跳出循环
      break;
    }
    
    // 检查数据是否完整
    if (currentIndex + 1 + len > arr.length) {
      console.error("Incomplete Wi-Fi data frame.");
      break;
    }

    const rssi = parseInt(arr[currentIndex + 1], 16);
    const nameBytes = arr.slice(currentIndex + 2, currentIndex + 1 + len);
    const name = String.fromCharCode(...nameBytes.map(hex => parseInt(hex, 16)));
    
    mDeviceEvent.notifyDeviceMsgEvent({
      'type': mDeviceEvent.XBLUFI_TYPE.TYPE_CONNECT_NEAR_ROUTER_LISTS,
      'result': true,
      'data': { "rssi": rssi, "SSID": decodeURIComponent(escape(name)) } // 保持和原逻辑一致的解码方式
    });
    
    // 移动索引到下一个Wi-Fi信息的开头
    currentIndex += (1 + len);
  }
}


/****************************** 对外导出 ***************************************/
module.exports = {
  init: init,
};