//
//  EZIoTBLECenterMgr.h
//  EZIoTBluetoothSDK
//
//  Created by yuqian on 2021/8/18.
//

#import <Foundation/Foundation.h>
#import "EZIoTBLECommonDefine.h"
#import "EZIoTPeripheral.h"
#import "EZIoTFeatureLiteConfigParam.h"
#import "EZIoTExtendAuthInfoParam.h"
#import "EZIoTBLECentralConfigParam.h"
#import "EZIoTBLECenterDelegate.h"


NS_ASSUME_NONNULL_BEGIN

@class EZIoTWiFiConfigParam;


/// 手机蓝牙中心模式管理类
@interface EZIoTBLECenterMgr : NSObject

@property (nonatomic, weak) id<EZIoTBLECenterDelegate> delegate;

/// 类初始化方法，该类可通过单例使用。通过单例使用时，可共享扫描到的外设信息。
+ (instancetype)sharedInstance;

/// 设置BLE配置参数，需在功能接口调用前设置
/// - Parameter configParam: 配置参数，详见参数内部介绍
- (void) setConfigParam:(EZIoTBLECentralConfigParam *)configParam;

/// 注册监听蓝牙外设连接更新
/// @param handler return 设备类型，例如 CS-C7-V100-G844WF
- (void)peripheralConnectChangeBlock:(EZIoTBLECenterPeripheralConnectDidChangedBlock)handler;

#pragma mark - Peripheral Scan & Connect

/// 请求蓝牙权限
- (void)requestBluetoothPermission:(EZIoTBLECenterStateDidChangedBlock)callback;

/// requestBluetoothPermission时centralMgr未初始化时，该类会持有EZIoTBLECenterStateDidChangedBlock，需要手动清除
- (void)clearBluetoothPermissionBlock;

/// 注册监听手机蓝牙状态变化
/// @param handler 手机蓝牙状态回调
- (void)registerCenterStateHandler:(EZIoTBLECenterStateDidChangedBlock)handler;

/// 注册监听外设状态变化
/// @param handler 外设状态回调
- (void)registerPeripheralStateHandler:(EZIoTBLEPeripheralStateDidChangedBlock)handler;

/// 扫描设备，该方法内部会内存缓存扫描结果
/// @param scanBlock 扫描回调，如扫描到设备scanBlock将会回调，可能会回调多次
- (void)scanPeripherals:(EZIoTBLEScanPeripheralsBlock)scanBlock;

/// 扫描设备，该方法内部会内存缓存扫描结果
/// @param allowDuplicate 扫描时是否对外设进行重复过滤。开启可能对电量和应用性能有影响，默认为NO；
/// @param scanBlock 扫描回调，如扫描到设备scanBlock将会回调，可能会回调多次
- (void)scanPeripherals:(BOOL)allowDuplicate
              scanBlock:(EZIoTBLEScanPeripheralsBlock)scanBlock;

/// 扫描设备，该方法内部会内存缓存扫描结果
/// @param scanAllDevice 扫描时是否运行返回周边所有设备，默认为NO，仅返回采用萤石蓝牙协议设备
/// @param allowDuplicate 扫描时是否对外设进行重复过滤。开启可能对电量和应用性能有影响，默认为NO；
/// @param filterBindDevice 扫描时是否过滤已绑定添加的设备，默认为NO；
/// @param scanBlock 扫描回调，如扫描到设备scanBlock将会回调，可能会回调多次
- (void)scanPeripherals:(BOOL)scanAllDevice
         allowDuplicate:(BOOL)allowDuplicate
       filterBindDevice:(BOOL)filterBindDevice
              scanBlock:(EZIoTBLEScanPeripheralsBlock)scanBlock;

/// 停止扫描，并清除扫描缓存。
/// 不需要扫描时建议关闭，节省手机电量
- (void)stopScan;

/// 注册扫描回调。
/// 该方法可以根据传入bizType，注册多个额外的扫描回调。可用于多个需要扫描结果的业务场景。
/// @param bizType 业务类型
/// @param handler 扫描回调
- (void) registerExtraScanResultBizType:(NSString *)bizType handler:(EZIoTBLEScanPeripheralsBlock)handler;

/// 移除扫描回调
/// @param bizType 业务类型，根据该业务类型移除对应的回调
- (void) removeExtraScanResultHandler:(NSString *)bizType;

/// 连接设备
/// @param p EZIoTPeripheral外设
/// @param success 连接成功回调
/// @param failure 连接失败回调
- (void)connectPeripheral:(EZIoTPeripheral *)p
                  success:(EZIoTBLEDidConnectPeripheralBlock)success
                  failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure;

/// 连接设备
/// @param p EZIoTPeripheral外设
/// @param success 连接成功回调
/// @param failure 连接失败回调
/// @param disconnected 设备断开连接回调
- (void)connectPeripheral:(EZIoTPeripheral *)p
                  success:(EZIoTBLEDidConnectPeripheralBlock)success
                  failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure
             disconnected:(EZIoTBLEDidDisconnectPeripheralBlock)disconnected;

/// 连接设备
/// @param p EZIoTPeripheral外设
/// @param timeout 当设置大于0时，采用timeout值。传 0 时，则采用无超时模式
/// @param success 连接成功回调
/// @param failure 连接失败回调
/// @param disconnected 设备断开连接回调
- (void) connectPeripheral:(NSArray <EZIoTPeripheral *>*)peripheral
                   timeout:(NSUInteger)timeout
                   success:(EZIoTBLEDidConnectPeripheralBlock)success
                   failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure
              disconnected:(EZIoTBLEDidDisconnectPeripheralBlock)disconnected;

/// 连接设备
/// @param macAddr 设备Mac地址
/// @param success 连接成功回调
/// @param failure 连接失败回调
- (void)connectPeripheralsWithMac:(NSString *)macAddr
                           success:(EZIoTBLEDidConnectPeripheralBlock)success
                           failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure;

/// 获取配对信息
/// @param macAddr 设备序列号
/// @param completion 成功回调
- (void)getPeripheralPair:(NSString *)deviceSerial
               completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 断开连接指定设备
/// @param p  EZIoTPeripheral外设
/// @param block 成功回调
- (void)stopConnect:(EZIoTPeripheral *)p complement:(EZIoTBLEDidDisconnectPeripheralBlock)block;

/// 断开所有连接的设备
/// @param block 成功回调
- (void)stopAllConnect:(EZIoTBLEDidDisconnectPeripheralBlock)block;

/// 清空扫描、连接外设缓存
- (void)resetCenterMgrAndCache;

/// 通过指定UUID获取外设实例对象
/// @param identifiers 外设标识UUIDs
- (NSArray<EZIoTPeripheral *> *)retrievePeripheralsWithIdentifiers:(NSArray<NSUUID *> *)identifiers;

/// 通过服务UUID获取已连接外设实例对象
/// @param serviceUUIDs 服务UUIDs
- (NSArray<EZIoTPeripheral *> *)retrieveConnectedPeripheralsWithServices:(NSArray<CBUUID *> *)serviceUUIDs;

/// 主动向外设请求蓝牙配对
/// @param deviceSerial 外设序列号
/// @param completion 响应回调
- (void) requestBlePeripheralPairing:(NSString *)deviceSerial completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 获取当前手机蓝牙状态
- (CBManagerState)getCurrentCentralState API_AVAILABLE(ios(10.0));

/// 当前是否处于扫描模式
- (BOOL)isCentralScaning;

/// 获取指定序列号设备（扫描外设列表中）
/// @param deviceSerial 设备序列号
- (EZIoTPeripheral *)getPeripheralWithDevSerial:(NSString *)deviceSerial;

/// 获取指定mac地址设备（扫描外设列表中）
/// @param mac mac地址
- (EZIoTPeripheral *)getPeripheralWithMac:(NSString *)mac;

/// 新增/修改扫描外设列表
/// @param peripherals 待操作外设对象
- (void)addOrUpdateScanPeripherals:(NSArray <EZIoTPeripheral *>*)peripherals;

/// 获取已扫描外设
- (NSArray <EZIoTPeripheral *>*)getAllScanedPeripheral;

/// 获取已连接外设
- (NSArray <EZIoTPeripheral *>*)getAllConnectedPeripheral;

/// 获取已连接的设备
/// @param deviceSerial 设备序列号
- (EZIoTPeripheral *) getConnectedPeripheralWithDevSerial:(NSString *)deviceSerial;

/// 获取指定设备的扫描状态
/// @param deviceSerial 设备序列号
- (BOOL)isPeripheralScanned:(NSString *)deviceSerial;

/// 获取指定设备的连接状态
/// @param deviceSerial 设备序列号
- (BOOL)isPeripheralConnected:(NSString *)deviceSerial;

/// 获取指定设备的连接认证状态
/// @param deviceSerial 设备序列号
- (BOOL)isPeripheralConnectedAndAuth:(NSString *)deviceSerial;

/// 获取指定设备的连接认证状态 1是未认证 2是认证中 3是认证成功
/// @param deviceSerial 设备序列号
- (int)getLocalAuthStatus:(NSString *)deviceSerial;

/// 获取指定设备是否支持控制
/// @param deviceSerial 设备序列号
- (BOOL)isPeripheralSupportControl:(NSString *)deviceSerial;

#pragma mark - Peripheral Auth & Bind

/// 开始进行双向认证
/// @param identifier peripheral.identifier.UUIDString
/// @param completion 完成回调
- (void)startDoubleAuthentication:(NSString *)identifier
                        completion:(EZIoTBLEDidRecivedAuthStatusBlock)completion;

/// 开始进行本地认证
/// @param deviceSerial deviceSerial
/// @param completion 完成回调
- (void)startLocalAuthentication:(NSString *)deviceSerial
                      verifyCode:(NSString *)verifyCode
                      completion:(EZIoTBLEDidRecivedAuthStatusBlock)completion;

/// 连接、双向认证二合一方法
/// @param deviceSerial 设备序列号
/// @param success 连接成功回调
/// @param failure 连接失败回调
- (void)connectAuth:(NSString *)deviceSerial
            success:(EZIoTBLEDidConnectPeripheralBlock)success
            failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure;

/// 连接、双向认证二合一方法
/// @param deviceSerial 设备序列号
/// @param success 连接成功回调
/// @param failure 连接失败回调
/// @param disconnected 设备断开回调
- (void)connectAuth:(NSString *)deviceSerial
            success:(EZIoTBLEDidConnectPeripheralBlock)success
            failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure
       disconnected:(EZIoTBLEDidDisconnectPeripheralBlock)disconnected;

/// 连接、双向认证二合一方法（自定义超时时间）
/// @param deviceSerial 设备序列号
/// @param timeout 超时时间
/// @param success 连接成功回调
/// @param failure 连接失败回调
/// @param disconnected 设备断开回调
- (void)connectAuth:(NSString *)deviceSerial
            timeout:(NSUInteger)timeout
            success:(EZIoTBLEDidConnectPeripheralBlock)success
            failure:(EZIoTBLEDidFailToConnectPeripheralBlock)failure
       disconnected:(EZIoTBLEDidDisconnectPeripheralBlock)disconnected;

- (void)sendExtendAuthInfo:(NSString *)identifier
                      param:(EZIoTExtendAuthInfoParam *)param;

/// 绑定设备
/// @param pid 设备Pid
/// @param devName 设备名称
/// @param deviceId 设备序列号
/// @param random 随机码，双向认证过程中获取，EZIoTPeripheral.randomKey
/// @param groupId 房间Id
/// @param completion 完成回调
- (void)bindDeviceWithPid:(NSString *)pid
                   devName:(NSString *)devName
                  deviceId:(NSString *)deviceId
                    random:(NSString *)random
                   groupId:(NSString *)groupId
                completion:(EZIoTBLEDidBindDeviceBlock)completion;

/// 发送随机数
/// @param deviceSerial 设备序列号
/// @param numberMsg 随机数。
- (void)sendRandomMsgCode:(NSString *)deviceSerial
                numberMsg:(NSString *)numberMsg
                completion:(EZIoTBLEUniversalSetResultBlock)completion;

#pragma mark - Peripheral Base Info

/// 获取设备信息，SDK双向认证前会内部调用一次
/// @param deviceSerial 设备序列号
/// @param completion 完成回调，获取成功后EZIoTPeripheral对象内会填充对应信息
- (void)getDeviceInfo:(NSString *)deviceSerial
            completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 获取设备MCU信息
/// @param deviceSerial 设备序列号
/// @param completion 完成回调，获取成功后EZIoTPeripheral对象内会填充对应信息
- (void)getDeviceMcuInfo:(NSString *)deviceSerial
              completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 获取设备能力集
/// @param deviceSerial 设备序列号
/// @param completion 完成回调，获取成功后EZIoTPeripheral对象内会填充对应信息
- (void) getCapability:(NSString *)deviceSerial
            completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 设备校时
/// @param deviceSerial 设备序列号
/// @param timeInterval 时间戳（since 1970）单位s，一般情况可通过getPlatfomUTCTime接口获取服务器当前的UTC时间
/// @param timezone 时区
/// @param daylightSaving 是否夏令时
/// @param completion 完成回调
- (void)setTime:(NSString *)deviceSerial
           time:(NSTimeInterval)timeInterval
       timezone:(NSTimeZone *)timezone
 daylightSaving:(BOOL)daylightSaving
     completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 设置设备绑定状态
/// @param deviceSerial 设备序列号
/// @param isBinded 是否绑定
/// @param completion 完成回调
- (void)setBindStatus:(NSString *)deviceSerial
             isBinded:(BOOL)isBinded
           completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 查询设备绑定状态
/// @param deviceSerial 设备序列号
/// @param completion 完成回调
- (void)queryBindStatus:(NSString *)deviceSerial
             completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 查询设备网络状态
/// @param deviceSerial 设备序列号
/// @param completion 完成回调
- (void)queryNetStatus:(NSString *)deviceSerial
            completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 设置设备APN信息
/// @param deviceSerial 设备序列号
/// @param apn 运营商接入点名称
/// @param userName 用户名
/// @param password 密码
/// @param authType 身份验证类型  None:1  PAP:2  CHAP:3  PAP-CHAP:4
/// @param completion 完成回调
- (void)setApnInfo:(NSString *)deviceSerial
               apn:(NSString *)apn
          userName:(NSString *)userName
          password:(NSString *)password
          authType:(NSString *)authType
        completion:(EZIoTBLEUniversalSetResultBlock)completion;


/// 设置设备APN信息（加密）
/// @param deviceSerial 设备序列号
/// @param apn 运营商接入点名称
/// @param userName 用户名
/// @param password 密码
/// @param authType 身份验证类型  None:1  PAP:2  CHAP:3  PAP-CHAP:4
/// @param completion 完成回调
- (void)setApnInfoEncrypt:(NSString *)deviceSerial
                      apn:(NSString *)apn
                 userName:(NSString *)userName
                 password:(NSString *)password
                 authType:(NSString *)authType
               completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 设置4G开关
/// @param deviceSerial 序列号
/// @param enable BOOL YES 打开 NO 关闭
/// @param completion 完成回调
- (void)setMobileNetEnable:(NSString *)deviceSerial
                    enable:(BOOL)enable
                completion:(EZIoTBLEUniversalSetResultBlock)completion;

#pragma mark - Peripheral WiFi Config

/// 设备WiFi配置
/// @param deviceSerial 设备序列号
/// @param param 配置参数
/// @param completion 完成回调
- (void)wifiConfig:(NSString *)deviceSerial
       configParam:(EZIoTWiFiConfigParam *)param
        completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 设备主备网络Wi-Fi设置
/// @param deviceSerial 设备序列号
/// @param param 通用参数
/// @param priority 网络优先级，0:主网络，1:备用网络
/// @param completion 回调
- (void)wifiConfig:(NSString *)deviceSerial
       configParam:(EZIoTWiFiConfigParam *)param
          priority:(NSUInteger)priority
        completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 设备 WiFI 列表查询
/// @param deviceSerial 设备序列号
/// @param completion 完成回调
- (void)getWiFiList:(NSString *)deviceSerial
         completion:(EZIoTBLEUniversalArrayResultBlock)completion;

/// 获取设备AP Wifi 热点信息
/// @param p deviceSerial 设备序列号
/// @param completion 完成回调
- (void)getDevWifiInfo:(NSString *)deviceSerial
            completion:(EZIoTBLEUniversalGETResultBlock)completion;

#pragma mark - Peripheral Dev Control

/// 获取属性功能点
/// @param deviceSerial 设备序列号
/// @param configParam 物模型参数
/// @param completion 完成回调
- (void)getPropFeature:(NSString *)deviceSerial
           configParam:(EZIoTFeatureLiteConfigParam *)configParam
             completion:(EZIoTBLEDevControlFeatureGetBlock)completion;

/// 设置属性功能点
/// @param deviceSerial 设备序列号
/// @param configParam 物模型参数
/// @param completion 完成回调
- (void)setPropFeature:(NSString *)deviceSerial
            configParam:(EZIoTFeatureLiteConfigParam *)configParam
             completion:(EZIoTBLEDevControlFeatureSetBlock)completion;

/// 设置操作功能点
/// @param deviceSerial 设备序列号
/// @param configParam 物模型参数
/// @param completion 完成回调
- (void)setActionFeature:(NSString *)deviceSerial
              configParam:(EZIoTFeatureLiteConfigParam *)configParam
               completion:(EZIoTBLEDevControlFeatureSetBlock)completion;

/// 注册设备功能点回调
/// @param callback 完成回调
- (void)registerFeatureListener:(EZIoTBLEDevControlFeatureReportBlock __nullable)callback;

/// 向设备发送操作响应结果
/// @param deviceSerial 设备序列号
/// @param seqNum 指令序号
/// @param cmdType 指令命令类型
/// @param code 错误码
/// @param msg 消息内容
- (void)sendOperationResult:(NSString *)deviceSerial
                     seqNum:(NSUInteger)seqNum
                    cmdType:(NSUInteger)cmdType
                       code:(NSInteger)code
                        msg:(NSString *)msg;


/// 透传数据传输，无需认证
/// @param deviceSerial 设备序列号
/// @param data 透传数据
/// @param completion 数据回调
- (void)sendTransparentNOAuthWithData:(NSString *)deviceSerial
                              content:(NSData *)data
                           completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 透传数据传输，需要认证
/// @param deviceSerial 设备序列号
/// @param data 透传数据
/// @param completion 数据回调
- (void)sendTransparentData:(NSString *)deviceSerial
                    content:(NSData *)data
                 completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 透传报文传输
/// @param deviceSerial 设备序列号
/// @param data 透传数据
/// @param completion 数据回调
- (void)sendTransparentMessage:(NSString *)deviceSerial
                      content:(NSData *)data
                   completion:(EZIoTBLEUniversalSetResultBlock)completion;


#pragma mark - Peripheral OTA Upgrade

/// 开始设备OTA升级
/// @param deviceSerial 设备序列号
/// @param pkgPath 升级包下载地址
/// @param upgradeMcu 是否是MCU升级
/// @param downloadProgress 下载进度回调
/// @param upgradeProgress 升级进度回调
/// @param completion 完成回调
- (void) startOTAUpgrade:(NSString *)deviceSerial
                 pkgPath:(NSString *)pkgPath
              upgradeMcu:(BOOL)upgradeMcu
        downloadProgress:(EZIoTBleDidRecivedProgressBlock)downloadProgress
         upgradeProgress:(EZIoTBleDidRecivedProgressBlock)upgradeProgress
              completion:(EZIoTBLEDidFinishedOTAUpdateBlock)completion;

/// 开始设备OTA升级（无需下载）
/// @param macAddr 设备Mac地址
/// @param pid 设备pid
/// @param version 设备版本
/// @param pgkFilePath 升级包本地URL
/// @param upgradeMcu 是否是MCU升级
/// @param progress 升级进度
/// @param completion 完成回调
- (void)startOTAUpgrade:(NSString *)macAddr
                    pid:(NSString *)pid
                version:(NSString *)version
            pgkFilePath:(NSString *)pgkFilePath
             upgradeMcu:(BOOL)upgradeMcu
               progress:(EZIoTBleDidRecivedProgressBlock)progress
             completion:(EZIoTBLEDidFinishedOTAUpdateBlock)completion;

/// 停止升级
- (void)stopOTAUpgrade;

/// 停止升级并取消当前任务
- (void)stopOTAUpgradeWithCancelTask;

#pragma mark - File Transfer

/// 文件传输
/// @param deviceSerial 设备序列号
/// @param filePath 文件本地URL，可选，如传入fileContent可不传
/// @param fileContent 文件内容，可选，如传入filePath可不传
/// @param fileType 文件类型 1:profile 2|3:保留
/// @param progress 传输进度
/// @param completion 完成进度
- (void) sendFile:(NSString *)deviceSerial
         filePath:(NSString * __nullable)filePath
      fileContent:(NSData * __nullable)fileContent
         fileType:(NSUInteger)fileType
         progress:(EZIoTBleDidRecivedProgressBlock)progress
       completion:(EZIoTBLEDidFinishedFileTransferBlock)completion;


#pragma mark - Dev Debug & Log

/// 日志设置
/// @param deviceSerial 设备序列号
/// @param isOn 日志记录开关：0 表示关闭，1 表示打开
/// @param logLevel 日志等级调整：低于且等于设定等级的日志，进行记录
/// 0 ASSERT 1 ERROR 2 WARNNING 3 INFO 4 DEBUG 5 VERBOSE
- (void)setDebugLog:(NSString *)deviceSerial
               isOn:(BOOL)isOn
           logLevel:(uint8_t)logLevel
         completion:(EZIoTBLEUniversalSetResultBlock)completion;

/// 日志拉取
/// @param deviceSerial 设备序列号
/// @param logNums 拉取日志条数。0-所有日志。
- (void)fetchDevLog:(NSString *)deviceSerial
            logNums:(NSUInteger)logNums
         completion:(EZIoTBLEFetchDevlogBlock)completion;

#pragma mark - 数据解密
/// 数据解密
/// @param deviceSerial 设备序列号
/// @param dataOrigin 原始数据
- (NSData *)parseResp:(NSString *)deviceSerial
                 data:(NSData *)dataOrigin;

@end

NS_ASSUME_NONNULL_END
