/*
 * Copyright (C) 2024-2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import "BluetoothPeripheralManager.h"
#import "BluetoothUntils.h"

#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) \
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) { \
    block(); \
} else { \
    dispatch_async(dispatch_get_main_queue(), block); \
}
#endif

@interface BluetoothPeripheralManager ()

@property(nonatomic, strong) NSMutableSet* connectedCentralSet;

- (void)reportCentralConnectedIfNeeded:(CBCentral*)central appId:(NSString*)strAppId;
- (BOOL)hasSubscribedCentral:(CBCentral*)central appId:(NSString*)strAppId;
- (CBMutableService*)getCurrentService:(NSString*)strKey appId:(NSString*)strAppId;
- (CBMutableCharacteristic*)getCurrentCharacteristic:(NSString*)serviceUUID
                                           charaUUID:(NSString*)charaUUID
                                               appId:(NSString*)strAppId;
- (NSString*)appIdForService:(CBService*)service;
- (NSData*)clientConfigurationValueForCharacteristic:(CBCharacteristic*)characteristic subscribed:(BOOL)subscribed;
- (void)descriptorWriteBlockRequest:(CBCentral*)central
                      characteristic:(CBCharacteristic*)character
                               value:(NSData*)value;

@end

@implementation BluetoothPeripheralManager

static const uint8_t CLIENT_CONFIG_DISABLE_VALUE = 0x00;
static const uint8_t CLIENT_CONFIG_NOTIFY_VALUE = 0x01;
static const uint8_t CLIENT_CONFIG_INDICATE_VALUE = 0x02;
static const NSUInteger CLIENT_CONFIG_VALUE_LENGTH = 2;
static NSString* const REQUEST_TYPE_READ = @"Read";
static NSString* const REQUEST_TYPE_WRITE = @"Write";

static NSString* BuildCharacteristicKey(NSString* serviceUuid, NSString* characterUuid)
{
    return [NSString stringWithFormat:@"%@:%@",
        [BluetoothUntils NormalizeBluetoothUuid:serviceUuid], [BluetoothUntils NormalizeBluetoothUuid:characterUuid]];
}

static NSString* BuildAppCharacteristicKey(NSString* strAppId, NSString* serviceUuid, NSString* characterUuid)
{
    NSString* characteristicKey = BuildCharacteristicKey(serviceUuid, characterUuid);
    if (strAppId.length == 0) {
        return characteristicKey;
    }
    return [NSString stringWithFormat:@"%@:%@", strAppId, characteristicKey];
}

static NSString* BuildAppRequestKey(NSString* strAppId, NSString* centralId, NSString* serviceUuid,
    NSString* characterUuid, NSString* requestType)
{
    return [NSString stringWithFormat:@"%@:%@:%@:%@", strAppId, centralId,
        BuildCharacteristicKey(serviceUuid, characterUuid), requestType];
}

static NSString* BuildConnectedCentralKey(NSString* strAppId, NSString* centralId)
{
    if (strAppId.length == 0) {
        return centralId;
    }
    return [NSString stringWithFormat:@"%@:%@", strAppId, centralId];
}

static NSMutableArray* MutableArrayFromDictionary(NSDictionary* dictionary, NSString* key)
{
    NSArray* array = dictionary[key];
    return array ? [NSMutableArray arrayWithArray:array] : [NSMutableArray array];
}

typedef NS_ENUM(NSInteger, CharacterSubscribe) {
    Subscribe = 0,
    UnSubscribe,
};

- (NSMutableDictionary*)requestDic
{
    if (_requestDic == nil) {
        _requestDic = [NSMutableDictionary dictionary];
    }
    return _requestDic;
}

- (NSMutableDictionary*)blockDic
{
    if (_blockDic == nil) {
        _blockDic = [NSMutableDictionary dictionary];
    }
    return _blockDic;
}

- (NSMutableDictionary*)servicesDic
{
    if (_servicesDic == nil) {
        _servicesDic = [NSMutableDictionary dictionary];
    }
    return _servicesDic;
}

- (NSMutableDictionary*)centralsDic
{
    if (_centralsDic == nil) {
        _centralsDic = [NSMutableDictionary dictionary];
    }
    return _centralsDic;
}

- (NSMutableSet*)connectedCentralSet
{
    if (_connectedCentralSet == nil) {
        _connectedCentralSet = [NSMutableSet set];
    }
    return _connectedCentralSet;
}

+ (BluetoothPeripheralManager*)sharedInstance
{
    static BluetoothPeripheralManager* bluetoothPeripheralManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      bluetoothPeripheralManager = [[BluetoothPeripheralManager alloc] init];
      bluetoothPeripheralManager.appId = 0;
    });
    return bluetoothPeripheralManager;
}

- (CBPeripheralManager *)peripheralManager {
    if (_peripheralManager == nil) {
        dispatch_main_async_safe(^{
            _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];
        });
    }
    return _peripheralManager;
}

- (void)createPeripheralManager
{
    if (self.peripheralManager == nil) {
        self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];
    }
}

- (int)getAppId
{
    self.appId += 1;
    return self.appId;
}

- (bool)isBleEnabled
{
    return bluetoothState;
}

- (void)closePeripheral:(NSString*)strAppId
{
    [self removeDic:self.servicesDic appId:strAppId];
    [self removeDic:self.blockDic appId:strAppId];
    [self removeDic:self.centralsDic appId:strAppId];
    [self removeSet:self.connectedCentralSet appId:strAppId];
}

- (void)removeDic:(NSMutableDictionary*)dic appId:(NSString*)strAppId
{
    NSString* strRmKey = [NSString stringWithFormat:@"%@:", strAppId];
    NSMutableArray* arrKeys = [NSMutableArray array];
    for (NSString* strkey in dic.allKeys) {
        if ([strkey hasPrefix:strRmKey]) {
            [arrKeys addObject:strkey];
        }
    }
    for (NSString* strkey in arrKeys) {
        if (dic == self.servicesDic) {
            CBMutableService* service = dic[strkey];
            [self.peripheralManager removeService:service];
        }
        [dic removeObjectForKey:strkey];
    }
}

- (void)removeSet:(NSMutableSet*)set appId:(NSString*)strAppId
{
    NSString* strRmKey = [NSString stringWithFormat:@"%@:", strAppId];
    NSMutableArray* arrKeys = [NSMutableArray array];
    for (NSString* strkey in set.allObjects) {
        if ([strkey hasPrefix:strRmKey]) {
            [arrKeys addObject:strkey];
        }
    }
    for (NSString* strkey in arrKeys) {
        [set removeObject:strkey];
    }
}

- (int)startAdvertising:(NSString*)strAppId
          isConnectable:(bool)isConnectable
           servicesUUID:(NSMutableArray*)serviceUUIDs
            serviceData:(NSMutableDictionary*)serviceData
      includeDeviceName:(bool)includeDeviceName
               duration:(int)duration
{
    NSNumber* isConnectableNumber = [NSNumber numberWithBool:isConnectable];

    NSMutableDictionary* advertisementData = [NSMutableDictionary dictionary];

    [advertisementData setObject:isConnectableNumber forKey:CBAdvertisementDataIsConnectable];
    [advertisementData setObject:serviceUUIDs forKey:CBAdvertisementDataServiceUUIDsKey];
    [advertisementData setObject:serviceData forKey:CBAdvertisementDataServiceDataKey];

    if (includeDeviceName) {
        UIDevice* device = [[UIDevice alloc] init];
        [advertisementData setObject:device.name forKey:CBAdvertisementDataLocalNameKey];
    }
    [self.peripheralManager startAdvertising:advertisementData];
    return BT_NO_ERROR;
}

- (int)stopAdvertising:(NSString*)strAppId
{
    [self.peripheralManager stopAdvertising];
    return BT_NO_ERROR;
}

- (int)addService:(CBMutableService*)service appId:(int)appId block:(AddServiceBlock)block
{
    NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
    NSString* strKey = [NSString stringWithFormat:@"%@:%@", strAppId, service.UUID.UUIDString];
    [self.blockDic setObject:block forKey:strKey];
    [self.servicesDic setObject:service forKey:strKey];
    [self.peripheralManager addService:service];
    return BT_NO_ERROR;
}

- (CBMutableService*)getCurrentService:(NSString*)strKey
{
    for (NSString* strServiceKey in self.servicesDic.allKeys) {
        NSArray<NSString*>* keyComponents = [strServiceKey componentsSeparatedByString:@":"];
        NSString* serviceUuid = keyComponents.count > 1 ? keyComponents.lastObject : strServiceKey;
        if ([BluetoothUntils IsSameBluetoothUuid:serviceUuid right:strKey]) {
            return self.servicesDic[strServiceKey];
        }
    }
    return nil;
}

- (CBMutableService*)getCurrentService:(NSString*)strKey appId:(NSString*)strAppId
{
    NSString* strPrefix = [NSString stringWithFormat:@"%@:", strAppId];
    for (NSString* strServiceKey in self.servicesDic.allKeys) {
        if (![strServiceKey hasPrefix:strPrefix]) {
            continue;
        }
        CBMutableService* currentService = self.servicesDic[strServiceKey];
        if ([BluetoothUntils IsSameBluetoothUuid:currentService.UUID.UUIDString right:strKey]) {
            return currentService;
        }
    }
    return nil;
}

- (int)removeService:(NSString*)strUUID appId:(int)appId
{
    NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
    NSString* strKey = [NSString stringWithFormat:@"%@:%@", strAppId, strUUID];
    if ([self.servicesDic.allKeys containsObject:strKey]) {
        CBMutableService* service = self.servicesDic[strKey];
        [self.peripheralManager removeService:service];
        return BT_NO_ERROR;
    }
    return BT_ERR_INTERNAL_ERROR;
}

- (int)notifyCharacteristicChanged:(NSString*)strDeviceId
                             appId:(int)appId
                       serviceUUID:(NSString*)serviceUUID
              notifyCharacteristic:(CBMutableCharacteristic*)notifyCharacteristic
{
    int ret = BT_ERR_INTERNAL_ERROR;
    if (strDeviceId.length == 0 || notifyCharacteristic == nil) {
        return ret;
    }
    NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
    CBMutableService* service = [self getCurrentService:serviceUUID appId:strAppId];
    if (service == nil) {
        return BT_ERR_GATT_SERVICE_NOT_FOUND;
    }
    for (NSUInteger i = 0; i < service.characteristics.count; i++) {
        CBMutableCharacteristic* character = (CBMutableCharacteristic*)service.characteristics[i];
        if (![BluetoothUntils IsSameBluetoothUuid:character.UUID.UUIDString
                                            right:notifyCharacteristic.UUID.UUIDString]) {
            continue;
        }
        character.value = notifyCharacteristic.value;
        if (!character.value) {
            return ret;
        }
        NSMutableArray<CBCentral*>* subscribedCentrals = [NSMutableArray array];
        for (CBCentral* subscribedCentral in character.subscribedCentrals) {
            if ([subscribedCentral.identifier.UUIDString isEqualToString:strDeviceId]) {
                [subscribedCentrals addObject:subscribedCentral];
                break;
            }
        }
        if (subscribedCentrals.count == 0) {
            return BT_ERR_GATT_CONNECTION_NOT_ESTABILISHED;
        }
        BOOL updated = [self.peripheralManager updateValue:character.value
                                         forCharacteristic:character
                                      onSubscribedCentrals:subscribedCentrals];
        ret = updated ? BT_NO_ERROR : BT_ERR_OPERATION_BUSY;
        break;
    }
    return ret;
}

- (int)sendRespondReadWithDeviceId:(NSString*)deviceId
                             appId:(int)appId
                       serviceUUID:(NSString*)serviceUUID
                     characterUUID:(NSString*)characterUUID
                              data:(NSData*)data
                            status:(int32_t)status
{
    if (status == BT_NO_ERROR && data == nil) {
        return BT_ERR_INTERNAL_ERROR;
    }
    NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
    NSString* strKey = BuildAppRequestKey(strAppId, deviceId, serviceUUID, characterUUID, REQUEST_TYPE_READ);
    if (![self.requestDic.allKeys containsObject:strKey]) {
        return BT_ERR_INTERNAL_ERROR;
    }
    CBATTRequest* request = self.requestDic[strKey];
    if (status == BT_NO_ERROR) {
        request.value = data;
    }
    [self sendRespond:strKey serviceUUID:serviceUUID characterUUID:characterUUID appId:strAppId status:status];
    return BT_NO_ERROR;
}

- (int)sendRespondWriteWithDeviceId:(NSString*)deviceId
                              appId:(int)appId
                        serviceUUID:(NSString*)serviceUUID
                      characterUUID:(NSString*)characterUUID
                             status:(int32_t)status
{
    NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
    NSString* strKey = BuildAppRequestKey(strAppId, deviceId, serviceUUID, characterUUID, REQUEST_TYPE_WRITE);
    if (![self.requestDic.allKeys containsObject:strKey]) {
        return BT_ERR_INTERNAL_ERROR;
    }
    [self sendRespond:strKey serviceUUID:serviceUUID characterUUID:characterUUID appId:strAppId status:status];
    return BT_NO_ERROR;
}

- (void)sendRespond:(NSString*)strKey
        serviceUUID:(NSString*)serviceUUID
      characterUUID:(NSString*)characterUUID
             appId:(NSString*)strAppId
             status:(int32_t)status
{
    CBATTError state = CBATTErrorRequestNotSupported;
    CBMutableCharacteristic* character = [self getCurrentCharacteristic:serviceUUID
                                                              charaUUID:characterUUID
                                                                  appId:strAppId];
    if (character && status == BT_NO_ERROR) {
        state = CBATTErrorSuccess;
    }
    CBATTRequest* request = self.requestDic[strKey];
    [self.peripheralManager respondToRequest:request withResult:state];

    [self.requestDic removeObjectForKey:strKey];
}

#pragma mark delegate
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager*)peripheral
{
    bluetoothState = false;
    if (peripheral.state == CBManagerStatePoweredOn) {
        bluetoothState = true;
    }
}

- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager*)peripheral error:(NSError*)error
{
    if (self.startAdvertisingBlock) {
        if (error) {
            self.startAdvertisingBlock(peripheral.isAdvertising, BT_ERR_INTERNAL_ERROR);
        } else {
            self.startAdvertisingBlock(peripheral.isAdvertising, BT_NO_ERROR);
        }
    }
}

- (void)peripheralManager:(CBPeripheralManager*)peripheral didAddService:(CBService*)service error:(NSError*)error
{
    int ret = error ? BT_ERR_INTERNAL_ERROR : BT_NO_ERROR;
    NSString* strKey = [NSString stringWithFormat:@"%@", service.UUID.UUIDString];
    for (NSString* strItem in self.blockDic.allKeys) {
        if ([strItem containsString:strKey]) {
            strKey = strItem;
            break;
        }
    }
    AddServiceBlock addServiceBlock = [self.blockDic objectForKey:strKey];
    if (addServiceBlock) {
        addServiceBlock(ret);
    }
}

- (void)peripheralManager:(CBPeripheralManager*)peripheral
                         central:(CBCentral*)central
    didSubscribeToCharacteristic:(CBCharacteristic*)characteristic
{
    NSString* strAppId = [self appIdForService:characteristic.service];
    if (strAppId.length == 0) {
        return;
    }
    NSString* strKey =
        BuildAppCharacteristicKey(strAppId, characteristic.service.UUID.UUIDString, characteristic.UUID.UUIDString);
    NSMutableArray* arrCentrals = MutableArrayFromDictionary(self.centralsDic, strKey);
    NSIndexSet* indexSet =
        [arrCentrals indexesOfObjectsPassingTest:^BOOL(CBCentral* _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) {
          return [obj.identifier isEqual:central.identifier];
        }];
    if (indexSet.count > 0) {
        [arrCentrals removeObjectsAtIndexes:indexSet];
        NSString* centralKey = BuildConnectedCentralKey(strAppId, central.identifier.UUIDString);
        [self.connectedCentralSet removeObject:centralKey];
    }
    [arrCentrals addObject:central];
    [self.centralsDic setObject:arrCentrals forKey:strKey];
    [self reportCentralConnectedIfNeeded:central appId:strAppId];
    NSData* value = [self clientConfigurationValueForCharacteristic:characteristic subscribed:YES];
    [self descriptorWriteBlockRequest:central characteristic:characteristic value:value];
}

- (void)peripheralManager:(CBPeripheralManager*)peripheral
                             central:(CBCentral*)central
    didUnsubscribeFromCharacteristic:(CBCharacteristic*)characteristic
{
    NSString* strAppId = [self appIdForService:characteristic.service];
    if (strAppId.length == 0) {
        return;
    }
    NSString* strKey =
        BuildAppCharacteristicKey(strAppId, characteristic.service.UUID.UUIDString, characteristic.UUID.UUIDString);

    NSMutableArray* arrCentrals = MutableArrayFromDictionary(self.centralsDic, strKey);
    NSIndexSet* indexSet =
        [arrCentrals indexesOfObjectsPassingTest:^BOOL(CBCentral* _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) {
          return [obj.identifier isEqual:central.identifier];
        }];
    if (arrCentrals.count == 0 || indexSet.count == 0) {
        return;
    }
    [arrCentrals removeObjectsAtIndexes:indexSet];
    [self.centralsDic setObject:arrCentrals forKey:strKey];
    NSData* value = [self clientConfigurationValueForCharacteristic:characteristic subscribed:NO];
    [self descriptorWriteBlockRequest:central characteristic:characteristic value:value];
    if (![self hasSubscribedCentral:central appId:strAppId]) {
        NSString* centralKey = BuildConnectedCentralKey(strAppId, central.identifier.UUIDString);
        [self.connectedCentralSet removeObject:centralKey];
    }
}

- (void)peripheralManager:(CBPeripheralManager*)peripheral didReceiveReadRequest:(CBATTRequest*)request
{
    NSString* strAppId = [self appIdForService:request.characteristic.service];
    if (strAppId.length == 0) {
        return;
    }
    NSString* strKey = BuildAppRequestKey(strAppId, request.central.identifier.UUIDString,
        request.characteristic.service.UUID.UUIDString, request.characteristic.UUID.UUIDString, REQUEST_TYPE_READ);
    [self.requestDic setObject:request forKey:strKey];
    [self reportCentralConnectedIfNeeded:request.central appId:strAppId];

    CBMutableCharacteristic* character = [self getCurrentCharacteristic:request.characteristic.service.UUID.UUIDString
                                                              charaUUID:request.characteristic.UUID.UUIDString
                                                                  appId:strAppId];
    if (character) {
        request.value = character.value;
        if (self.characterReadBlock) {
            self.characterReadBlock(request.central.identifier.UUIDString, character);
        }
    }
}

- (void)peripheralManager:(CBPeripheralManager*)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest*>*)requests
{
    for (CBATTRequest* request in requests) {
        NSString* strAppId = [self appIdForService:request.characteristic.service];
        if (strAppId.length == 0) {
            continue;
        }
        NSString* strKey = BuildAppRequestKey(strAppId, request.central.identifier.UUIDString,
            request.characteristic.service.UUID.UUIDString, request.characteristic.UUID.UUIDString, REQUEST_TYPE_WRITE);
        [self.requestDic setObject:request forKey:strKey];
        [self reportCentralConnectedIfNeeded:request.central appId:strAppId];

        CBMutableCharacteristic* character =
            [self getCurrentCharacteristic:request.characteristic.service.UUID.UUIDString
                                 charaUUID:request.characteristic.UUID.UUIDString
                                     appId:strAppId];
        if (character) {
            character.value = request.value;
            [self writeBlockRequest:request characteristic:character];
        }
    }
}

- (void)connectDeviceCallBack:(CBCentral*)central peripheralState:(CBPeripheralState)peripheralState
{
    if (self.connectDeviceBlock) {
        self.connectDeviceBlock(peripheralState, central.identifier.UUIDString);
    }
}

- (void)reportCentralConnectedIfNeeded:(CBCentral*)central appId:(NSString*)strAppId
{
    if (central == nil) {
        return;
    }
    NSString* centralId = central.identifier.UUIDString;
    NSString* centralKey = BuildConnectedCentralKey(strAppId, centralId);
    if (centralId.length == 0 || self.connectDeviceBlock == nil ||
        [self.connectedCentralSet containsObject:centralKey]) {
        return;
    }
    [self.connectedCentralSet addObject:centralKey];
    [self connectDeviceCallBack:central peripheralState:CBPeripheralStateConnected];
}

- (BOOL)hasSubscribedCentral:(CBCentral*)central appId:(NSString*)strAppId
{
    if (central == nil) {
        return NO;
    }
    NSString* strPrefix = strAppId.length == 0 ? nil : [NSString stringWithFormat:@"%@:", strAppId];
    for (NSString* strKey in self.centralsDic.allKeys) {
        if (strPrefix != nil && ![strKey hasPrefix:strPrefix]) {
            continue;
        }
        NSArray* centrals = self.centralsDic[strKey];
        for (CBCentral* subscribedCentral in centrals) {
            if ([subscribedCentral.identifier isEqual:central.identifier]) {
                return YES;
            }
        }
    }
    return NO;
}

- (NSString*)appIdForService:(CBService*)service
{
    if (service == nil) {
        return nil;
    }
    for (NSString* strServiceKey in self.servicesDic.allKeys) {
        CBService* currentService = self.servicesDic[strServiceKey];
        if (currentService == service) {
            return [strServiceKey componentsSeparatedByString:@":"].firstObject;
        }
    }
    NSString* matchedAppId = nil;
    for (NSString* strServiceKey in self.servicesDic.allKeys) {
        CBService* currentService = self.servicesDic[strServiceKey];
        if ([BluetoothUntils IsSameBluetoothUuid:currentService.UUID.UUIDString right:service.UUID.UUIDString]) {
            if (matchedAppId != nil) {
                NSLog(@"Duplicate service UUID registered for multiple appId.");
                return nil;
            }
            matchedAppId = [strServiceKey componentsSeparatedByString:@":"].firstObject;
        }
    }
    return matchedAppId;
}

- (void)writeBlockRequest:(CBATTRequest*)request characteristic:(CBMutableCharacteristic*)character
{
    if (self.characterWriteBlock) {
        self.characterWriteBlock(request.central.identifier.UUIDString, character);
    }
}

- (NSData*)clientConfigurationValueForCharacteristic:(CBCharacteristic*)characteristic subscribed:(BOOL)subscribed
{
    uint8_t value[CLIENT_CONFIG_VALUE_LENGTH] = { CLIENT_CONFIG_DISABLE_VALUE, CLIENT_CONFIG_DISABLE_VALUE };
    if (!subscribed || characteristic == nil) {
        return [NSData dataWithBytes:value length:CLIENT_CONFIG_VALUE_LENGTH];
    }
    if ((characteristic.properties & CBCharacteristicPropertyNotify) != 0 ||
        (characteristic.properties & CBCharacteristicPropertyNotifyEncryptionRequired) != 0) {
        value[0] = CLIENT_CONFIG_NOTIFY_VALUE;
    } else if ((characteristic.properties & CBCharacteristicPropertyIndicate) != 0 ||
        (characteristic.properties & CBCharacteristicPropertyIndicateEncryptionRequired) != 0) {
        value[0] = CLIENT_CONFIG_INDICATE_VALUE;
    }
    return [NSData dataWithBytes:value length:CLIENT_CONFIG_VALUE_LENGTH];
}

- (void)descriptorWriteBlockRequest:(CBCentral*)central characteristic:(CBCharacteristic*)character value:(NSData*)value
{
    if (self.descriptorWriteBlock == nil) {
        return;
    }
    self.descriptorWriteBlock(central.identifier.UUIDString, character, value);
}

- (void)notifyBlockRequest:(CBCentral*)central characteristic:(CBCharacteristic*)character state:(int)state
{
    if (self.characterNotifyBlock) {
        self.characterNotifyBlock(central.identifier.UUIDString, character, state);
    }
}

- (CBMutableCharacteristic*)getCurrentCharacteristic:(NSString*)serviceUUID
                                          charaUUID:(NSString*)charaUUID
                                              appId:(NSString*)strAppId
{
    CBMutableService* service = [self getCurrentService:serviceUUID appId:strAppId];
    if (service == nil) {
        return nil;
    }

    CBMutableCharacteristic* currentCharacter = nil;

    for (CBMutableCharacteristic* character in service.characteristics) {
        if ([BluetoothUntils IsSameBluetoothUuid:character.UUID.UUIDString right:charaUUID]) {
            currentCharacter = character;
            break;
        }
    }

    return currentCharacter;
}

@end