/*
 * Copyright (c) 2023-2025 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 <Foundation/Foundation.h>
#import <objc/runtime.h>

#import "BridgeBinaryCodec.h"
#import "BridgeCodecUtil.h"
#import "BridgeGCDTaskQueue.h"
#import "BridgeJsonCodec.h"
#import "BridgeManagerHolder.h"
#import "BridgePlugin+internal.h"
#import "BridgePlugin+jsMessage.h"
#import "BridgePlugin.h"
#import "BridgePluginManager+internal.h"
#import "BridgeTaskQueueHandler.h"
#import "ResultValue.h"

#include "adapter/ios/capability/bridge/bridge_manager.h"
#include "adapter/ios/capability/bridge/buffer_mapping.h"
#include "base/log/log.h"
#include "core/common/ace_engine.h"
#include "core/common/container.h"

@interface BridgePluginManager () 
@property (nonatomic, assign) BOOL willTerminate;
@property (nonatomic, strong) NSMutableDictionary<NSString*, BridgePlugin*>* bridgeMap;
@property (nonatomic, strong) NSMutableDictionary<NSString*, BridgeTaskQueueHandler*>* bridgeQueueMap;
@end

@implementation BridgePluginManager (internal)

const std::vector<uint8_t> ConvertToVector(NSData* data) {
    const uint8_t* bytes = (const uint8_t*)data.bytes;
    return std::vector<uint8_t>(bytes, bytes + data.length);
}

static std::unique_ptr<OHOS::Ace::Platform::BufferMapping> NSDataToBufferMapping(NSData* nsData) {
    if (nsData == nil) {
        return std::make_unique<OHOS::Ace::Platform::BufferMapping>
                (OHOS::Ace::Platform::BufferMapping::Copy(nullptr, 0));
    }
    uint8_t* dataBytes = (uint8_t*)[nsData bytes];
    size_t dataSize = [nsData length];
    return std::make_unique<OHOS::Ace::Platform::BufferMapping>
                (OHOS::Ace::Platform::BufferMapping::Copy(dataBytes, dataSize));
}

static NSData* ConvertBufferMappingToNSData(std::unique_ptr<OHOS::Ace::Platform::BufferMapping> result) {
    if (!result) {
        return nil;
    }
    const uint8_t* bytes = result->GetMapping();
    size_t length = result->GetSize();
    return [NSData dataWithBytes:bytes length:length];
}

+ (instancetype)sharedInstance {
    static BridgePluginManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[BridgePluginManager alloc] initBridgePluginManager];
    });
    return instance;
}

- (instancetype)initBridgePluginManager {
    self = [super self];
    if (self) {
        self.bridgeMap = [[NSMutableDictionary alloc] init];
        self.bridgeQueueMap = [[NSMutableDictionary alloc] init];
    }
    return self;
}

#pragma mark - public set get
static char kWillTerminateKey;
static char kPluginInstanceIdKey;
static char kBridgeMapKey;
static char kBridgeQueueMapKey;

- (void)setWillTerminate:(BOOL)willTerminate {
    objc_setAssociatedObject(self, &kWillTerminateKey, @(willTerminate), OBJC_ASSOCIATION_ASSIGN);
}

- (BOOL)willTerminate {
    NSNumber* value = objc_getAssociatedObject(self, &kWillTerminateKey);
    return [value boolValue];
}

- (void)setBridgeMap:(NSMutableDictionary<NSString*,BridgePlugin*>*)bridgeMap {
    objc_setAssociatedObject(self, &kBridgeMapKey, bridgeMap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSMutableDictionary<NSString*,BridgePlugin*>*)bridgeMap {
    return objc_getAssociatedObject(self, &kBridgeMapKey);
}

- (void)setBridgeQueueMap:(NSMutableDictionary<NSString*,BridgePlugin*>*)bridgeQueueMap {
    objc_setAssociatedObject(self, &kBridgeQueueMapKey, bridgeQueueMap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSMutableDictionary<NSString*, BridgeTaskQueueHandler*>*)bridgeQueueMap {
    return objc_getAssociatedObject(self, &kBridgeQueueMapKey);
}

#pragma mark - public method

- (BOOL)innerRegisterBridgePlugin:(NSString*)bridgeName
                bridgePlugin:(BridgePlugin*)bridgePlugin {
    if (!bridgeName.length || !bridgePlugin) {
        LOGE("register failed, bridgename : %{public}s", bridgeName.UTF8String);
        return NO;
    }
    if ([self.bridgeMap.allKeys containsObject:bridgeName]) {
        if ([self innerUnRegisterBridgePlugin:bridgeName]) {
            LOGI("%{public}s Duplicate registration, delete previously registered bridge", bridgeName.UTF8String);
        }
    }
    [self.bridgeMap setObject:bridgePlugin forKey:bridgeName];
    std::string c_bridgeName = [bridgeName UTF8String];
    int32_t bridgeType = OHOS::Ace::Platform::BridgeManager::GetBridgeType(c_bridgeName);
    if (OHOS::Ace::Platform::BridgeManager::JSBridgeExists(c_bridgeName) &&
        bridgeType == bridgePlugin.type) {
        [bridgePlugin onRegisterResult:true];
    }
    if (bridgePlugin.taskOption) {
        if (![self.bridgeQueueMap.allKeys containsObject:bridgeName]) {
            BridgeTaskQueueHandler * handler = [[BridgeTaskQueueHandler alloc] init];
            handler.isUseTaskQueue = true;
            handler.isSerial = bridgePlugin.taskOption.isSerial;
            [self.bridgeQueueMap setObject:handler forKey:bridgeName];
        }
    }
    return YES;
}

- (BOOL)innerUnRegisterBridgePlugin:(NSString*)bridgeName {
    if (!bridgeName.length) {
        return false;
    }
    @synchronized(self) {
        [self.bridgeMap removeObjectForKey:bridgeName];
        [self.bridgeQueueMap removeObjectForKey:bridgeName];
    }
    return true;
}

- (void)unRegisterBridgePlugin {
    @synchronized(self) {
        [self.bridgeMap removeAllObjects];
    }
}

- (void)jsCallMethod:(NSString*)bridgeName methodName:(NSString*)methodName param:(NSString*)param {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsCallMethodInner:bridgeName methodName:methodName param:param];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
}

- (NSString*)jsCallMethodSync:(NSString*)bridgeName methodName:(NSString*)methodName param:(NSString*)param {
    @autoreleasepool {
        BridgePlugin* bridgePlugin = static_cast<BridgePlugin*>([self getPluginWithBridgeName:bridgeName]);
        if (!bridgePlugin || bridgePlugin.type != JSON_TYPE) {
            NSNumber* numberErrorCode = [NSNumber numberWithInt:BRIDGE_INVALID];
            NSString* strErrorMessage = BRIDGE_INVALID_MESSAGE;
            NSString* strResult = @"";
            NSDictionary* dict = @{ @"errorCode" : numberErrorCode, @"errorMessage" : strErrorMessage, @"result" : strResult };
            NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
            NSString* resultJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
            return resultJson;
        }
        NSMutableArray* mArray = [NSMutableArray array];
        if (param) {
            id methodParam = [JsonHelper objectWithJSONString:param];
            if (methodParam && [methodParam isKindOfClass:NSDictionary.class]) {
                NSDictionary* methodDic = (NSDictionary*)methodParam;
                for (int i = 0; i < methodDic.allKeys.count; i++) {
                    id argument = [methodDic objectForKey:[NSString stringWithFormat:@"%d", i]];
                    [mArray addObject:argument];
                }
            }
        }
        MethodData* methodData = [[MethodData alloc] initMethodWithName:methodName parameter:mArray];
        return [bridgePlugin jsCallMethodSync:methodData];
    }
}

- (void)jsSendMethodResult:(NSString*)bridgeName methodName:(NSString*)methodName result:(id)result {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsSendMethodResultInner:bridgeName methodName:methodName result:result];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
}

- (void)jsSendMessage:(NSString*)bridgeName data:(id)data {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsSendMessageInner:bridgeName data:data];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
}

- (void)jsSendMessageResponse:(NSString*)bridgeName data:(NSString*)data {
    @autoreleasepool {
        __weak BridgePluginManager* weakSelf = self;
        BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
            [weakSelf jsSendMessageResponseInner:bridgeName data:data];
        }];
        [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
    }
}

- (void)jsCancelMethod:(NSString*)bridgeName methodName:(NSString*)methodName {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsCancelMethodInner:bridgeName methodName:methodName];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
}

- (void)jsSendMessageBinary:(NSString*)bridgeName data:(id)data {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsSendMessageBinaryInner:bridgeName data:data];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
}

- (void)jsCallMethodBinary:(NSString*)bridgeName
                methodName:(NSString*)methodName
                    param:(NSData*)data {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsCallMethodBinaryInner:bridgeName methodName:methodName param:data];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];
}

- (void)jsSendMethodResultBinary:(NSString*)bridgeName
                    methodName:(NSString*)methodName
                    errorCode:(int)errorCode
                    errorMessage:(NSString*)errorMessage
                    result:(id)result {
    __weak BridgePluginManager* weakSelf = self;
    BridgeTaskInfo* taskInfo = [BridgeTaskInfo bridgeTaskInfoFactory:bridgeName
                                        queueInOutType:INPUT handler:^{
        [weakSelf jsSendMethodResultBinaryInner:bridgeName methodName:methodName errorCode:errorCode
                errorMessage:errorMessage result:result];
    }];
    [self dispatchTaskInQueueHandlerWithTaskInfo:taskInfo];                  
}

- (void)platformCallMethod:(NSString*)bridgeName
                        methodName:(NSString*)methodName
                            param:(NSArray* _Nullable)params 
                        reultValueCallback:(void (^)(ResultValue* _Nullable reultValue))callback {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
        [weakSelf platformCallMethodInner:bridgeName methodName:methodName param:params reultValueCallback:callback];
    })];
}

- (void)platformSendMessage:(NSString*)bridgeName data:(id)data {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
        [weakSelf platformSendMessageInner:bridgeName data:data];
    })];
}

- (void)platformSendMessageResponse:(NSString*)bridgeName data:(id)data {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
        [weakSelf platformSendMessageResponseInner:bridgeName data:data];
    })];
}

- (void)platformSendMethodResult:(NSString*)bridgeName methodName:(NSString*)methodName
                    errorCode:(int)errorCode
                    errorMessage:(NSString*)errorMessage
                    result:(id)result {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
      RawValue* resultValue = [RawValue rawValueRresult:result
                                           errorCode:errorCode
                                           errorMessage:errorMessage.length ? errorMessage : @""];
      NSString* jsonString = [[BridgeJsonCodec sharedInstance] encode:resultValue];
      [weakSelf platformSendMethodResultInner:bridgeName methodName:methodName result:jsonString];
    })];
}

- (void)platformSendMessageResponseErrorInfo:(NSString*)bridgeName errorCode:(ErrorCode)errorCode {
    RawValue* resultValue = [RawValue rawValueRresult:@"errorCode" errorCode:errorCode errorMessage:@""];
    NSString* jsonString = [[BridgeJsonCodec sharedInstance] encode:resultValue];

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_data;
    if (jsonString) {
        c_data = [jsonString UTF8String];
    }
    OHOS::Ace::Platform::BridgeManager::PlatformSendMessageResponse(c_bridgeName, c_data);
}

- (void)platformSendMethodResultErrorInfo:(NSString*)bridgeName
                methodName:(NSString*)methodName errorCode:(ErrorCode)errorCode {
    RawValue* resultValue = [RawValue resultErrorCode:errorCode errorMessage:ResultValueError(errorCode)];
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    NSString* jsonString = [[BridgeJsonCodec sharedInstance] encode:resultValue];
    [self platformSendMethodResultInner:bridgeName methodName:methodName result:jsonString];
}

- (void)platformWillTerminate {
    if (self.willTerminate) {
        return;
    }
    self.willTerminate = true;
    OHOS::Ace::Platform::BridgeManager::PlatformSendWillTerminate();
}

- (void)platformSendMethodResultBinary:(NSString*)bridgeName
                            methodName:(NSString*)methodName
                            errorCode:(int)errorCode
                            errorMessage:(NSString*)errorMessage
                                result:(id)result {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
        [weakSelf platformSendMethodResultBinaryInner:bridgeName methodName:methodName
                                errorCode:errorCode
                                errorMessage:errorMessage
                                result:result];
    })];
}

- (void)platformSendMessageBinary:(NSString*)bridgeName
                            data:(id)data {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
        [weakSelf platformSendMessageBinaryInner:bridgeName data:data];
    })];
}

- (void)platformCallMethodBinary:(NSString*)bridgeName
                                methodName:(NSString*)methodName
                                param:(NSArray* _Nullable)params
                            reultValueCallback:(void (^)(ResultValue* _Nullable reultValue))callback {
    __weak BridgePluginManager* weakSelf = self;
    [[BridgeGCDTaskQueue sharedInstance] gcdDispatchAsync:(^{
        [weakSelf platformCallMethodBinaryInner:bridgeName methodName:methodName param:params reultValueCallback:callback];
    })];
}

#pragma mark - private method
- (void)jsCallMethodInner:(NSString*)bridgeName methodName:(NSString*)methodName param:(NSString*)param {
    @autoreleasepool {
        BridgePlugin* bridgePlugin = static_cast<BridgePlugin*>([self getPluginWithBridgeName:bridgeName]);
        if (!bridgePlugin) {
            [self platformSendMethodResultErrorInfo:bridgeName methodName:methodName errorCode:BRIDGE_INVALID];
            return;
        }
        if (bridgePlugin.type != JSON_TYPE) {
            [self platformSendMethodResultErrorInfo:bridgeName methodName:methodName
                                                    errorCode:BRIDGE_CODEC_TYPE_MISMATCH];
            return;
        }
        NSMutableArray* mArray = [NSMutableArray array];
        if (param) {
            id methodParam = [JsonHelper objectWithJSONString:param];
            if (methodParam && [methodParam isKindOfClass:NSDictionary.class]) {
                NSDictionary* methodDic = (NSDictionary*)methodParam;
                for (int i = 0; i < methodDic.allKeys.count; i++) {
                    id argument = [methodDic objectForKey:[NSString stringWithFormat:@"%d", i]];
                    [mArray addObject:argument];
                }
            }
        }
        MethodData* methodData = [[MethodData alloc] initMethodWithName:methodName
                                                    parameter:mArray.copy];
        [bridgePlugin jsCallMethod:methodData];
    }
}

- (void)jsSendMethodResultInner:(NSString*)bridgeName methodName:(NSString*)methodName result:(id)result {
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin) {
        [self platformSendMethodResultErrorInfo:bridgeName methodName:methodName errorCode:BRIDGE_INVALID];
        return;
    }
    if (bridgePlugin.type != JSON_TYPE) {
        [self platformSendMethodResultErrorInfo:bridgeName methodName:methodName 
                                                        errorCode:BRIDGE_CODEC_TYPE_MISMATCH];
        return;
    }

    RawValue* rawValue = [[BridgeJsonCodec sharedInstance] decode:result];
    ResultValue* resultValue = [[ResultValue alloc] init];
    resultValue.result = rawValue.result ?: @"";
    resultValue.errorCode = (ErrorCode)rawValue.errorCode;
    resultValue.errorMessage = rawValue.errorMessage ?: @"";
    resultValue.methodName = methodName;
    [bridgePlugin jsSendMethodResult:resultValue];
}

- (void)jsSendMessageInner:(NSString*)bridgeName data:(id)data {
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin) {
        [self platformSendMessageResponseErrorInfo:bridgeName errorCode:BRIDGE_NAME_ERROR];
        return;
    }
    if (bridgePlugin.type != JSON_TYPE) {
        [self platformSendMessageResponseErrorInfo:bridgeName errorCode:BRIDGE_CODEC_TYPE_MISMATCH];
        return;
    }

    RawValue* rawValue = [[BridgeJsonCodec sharedInstance] decode:data];
    [bridgePlugin jsSendMessage:rawValue.result];
}

- (void)jsSendMessageResponseInner:(NSString*)bridgeName data:(NSString*)data {
    @autoreleasepool {
        BridgePlugin* bridgePlugin = static_cast<BridgePlugin*>([self getPluginWithBridgeName:bridgeName]);
        if (!bridgePlugin) {
            return;
        }
        RawValue* rawValue = [[BridgeJsonCodec sharedInstance] decode:data];
        [bridgePlugin jsSendMessageResponse:rawValue.result];
    }
}

- (void)jsCancelMethodInner:(NSString*)bridgeName methodName:(NSString*)methodName {
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin) {
        return;
    }
    [bridgePlugin jsCancelMethod:bridgeName methodName:methodName];
}

- (void)platformCallMethodInner:(NSString*)bridgeName
                        methodName:(NSString*)methodName
                            param:(NSArray* _Nullable)params 
                        reultValueCallback:(void (^)(ResultValue* _Nullable reultValue))callback {
    ResultValue* resultValue = [[ResultValue alloc] init];
    if (!bridgeName.length) {
        resultValue.errorCode = BRIDGE_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_NAME_ERROR_MESSAGE;
        if (callback) {
            callback(resultValue);
        }
        return;
    }

    if (!methodName.length) {
        resultValue.errorCode = BRIDGE_METHOD_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_METHOD_NAME_ERROR_MESSAGE;
        if (callback) {
            callback(resultValue);
        }
        return;
    }
    NSString* jsonString = nil;
    if (params.count > 0) {
        NSMutableDictionary* mDic = [NSMutableDictionary dictionary];
        for (int i = 0; i < params.count; i++) {
            [mDic setObject:params[i] forKey:[NSString stringWithFormat:@"%d", i]];
        }
        jsonString = [JsonHelper jsonStringWithObject:mDic.copy];
    }

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_methodName = [methodName UTF8String];
    std::string c_param = [jsonString.length ? jsonString : @"" UTF8String];
    OHOS::Ace::Platform::BridgeManager::PlatformCallMethod(c_bridgeName, c_methodName, c_param);
}

- (ResultValue*)platformCallMethodInnerReult:(NSString*)bridgeName
                                  methodName:(NSString*)methodName
                                       param:(NSArray* _Nullable)params {
    ResultValue* resultValue = [[ResultValue alloc] init];
    if (!bridgeName.length) {
        resultValue.errorCode = BRIDGE_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_NAME_ERROR_MESSAGE;
        return resultValue;
    }
    if (!methodName.length) {
        resultValue.errorCode = BRIDGE_METHOD_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_METHOD_NAME_ERROR_MESSAGE;
        return resultValue;
    }
    NSString* jsonString = nil;
    if (params.count > 0) {
        NSMutableDictionary* mDic = [NSMutableDictionary dictionary];
        for (int i = 0; i < params.count; i++) {
            [mDic setObject:params[i] forKey:[NSString stringWithFormat:@"%d", i]];
        }
        jsonString = [JsonHelper jsonStringWithObject:mDic.copy];
    }

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_methodName = [methodName UTF8String];
    std::string c_param = [jsonString.length ? jsonString : @"" UTF8String];
    std::string result =
        OHOS::Ace::Platform::BridgeManager::PlatformCallMethodResult(c_bridgeName, c_methodName, c_param);
    NSString* strResult = [NSString stringWithCString:result.c_str() encoding:NSUTF8StringEncoding];
    RawValue* rawValue = [[BridgeJsonCodec sharedInstance] decode:strResult];
    resultValue.result = rawValue.result ?: @"";
    resultValue.errorCode = (ErrorCode)rawValue.errorCode;
    resultValue.errorMessage = rawValue.errorMessage ?: @"";
    resultValue.methodName = methodName;
    return resultValue;
}

- (void)platformSendMessageInner:(NSString*)bridgeName data:(id)data {
    if (!bridgeName.length) {
        LOGE("bridgeName is null");
        return;
    }
    RawValue* rawValue = [RawValue rawValueResult:data errorCode:0];
    NSString* string = [[BridgeJsonCodec sharedInstance] encode:rawValue];

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_data;
    if (string) {
        c_data = [string UTF8String];
    }
    OHOS::Ace::Platform::BridgeManager::PlatformSendMessage(c_bridgeName, c_data);
}

- (void)platformSendMessageResponseInner:(NSString*)bridgeName data:(id)data {
    if (!bridgeName.length) {
        LOGE("bridgeName is null");
        return;
    }
    RawValue* rawValue = [RawValue rawValueResult:data errorCode:0];
    NSString* jsonString = [[BridgeJsonCodec sharedInstance] encode:rawValue];

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_data;
    if (jsonString) {
        c_data = [jsonString UTF8String];
    }
    OHOS::Ace::Platform::BridgeManager::PlatformSendMessageResponse(c_bridgeName, c_data);
}

- (void)platformSendMethodResultInner:(NSString*)bridgeName methodName:(NSString*)methodName result:(NSString*)result {
    if (!bridgeName.length) {
        LOGE("bridgeName is null");
        return;
    }
    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_methodName = [methodName UTF8String];
    std::string c_result;
    if (result) {
        c_result = [result UTF8String];
    }
    OHOS::Ace::Platform::BridgeManager::PlatformSendMethodResult(c_bridgeName, c_methodName, c_result);
}

- (void)jsSendMessageBinaryInner:(NSString*)bridgeName data:(id)data {
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin) {
        [self platformSendMessageResponseErrorInfo:bridgeName errorCode:BRIDGE_NAME_ERROR];
        return;
    }
    if (bridgePlugin.type != BINARY_TYPE) {
        [self platformSendMessageResponseErrorInfo:bridgeName errorCode:BRIDGE_CODEC_TYPE_MISMATCH];
        return;
    }
    id oc_data = [[BridgeBinaryCodec sharedInstance] decode:data];
    [bridgePlugin jsSendMessage:oc_data];
}

- (void)jsCallMethodBinaryInner:(NSString*)bridgeName methodName:(NSString*)methodName param:(NSData*)data {
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin) {
        [self platformSendMethodResultErrorInfo:bridgeName methodName:methodName errorCode:BRIDGE_INVALID];
        return;
    }
    if (bridgePlugin.type != BINARY_TYPE) {
        [self platformSendMethodResultErrorInfo:bridgeName
                methodName:methodName errorCode:BRIDGE_CODEC_TYPE_MISMATCH];
        return;
    }
    NSArray* oc_parameter;
    if (data && data.length != 0) {
        BridgeCodecType binaryType = (BridgeCodecType)[[BridgeBinaryCodec sharedInstance] getBinaryType:data];
        id decode_data = [[BridgeBinaryCodec sharedInstance] decode:data];
        if (binaryType == T_COMPOSITE_LIST) {
            oc_parameter = decode_data;
        } else if (decode_data) {
            oc_parameter = @[decode_data];
        }
    }

    MethodData* methodData = [[MethodData alloc] initMethodWithName:methodName
                                                    parameter:oc_parameter.copy];
    [bridgePlugin jsCallMethod:methodData];
}

- (ResultValue*)jsCallMethodBinarySync:(NSString*)bridgeName methodName:(NSString*)methodName param:(NSData*)data
{
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin || bridgePlugin.type != BINARY_TYPE) {
        ResultValue* resultValue = [[ResultValue alloc] init];
        resultValue.errorCode = BRIDGE_INVALID;
        resultValue.errorMessage = BRIDGE_INVALID_MESSAGE;
        return resultValue;
    }
    NSArray* oc_parameter = @[];
    if (data && data.length != 0) {
        BridgeCodecType binaryType = (BridgeCodecType)[[BridgeBinaryCodec sharedInstance] getBinaryType:data];
        id decode_data = [[BridgeBinaryCodec sharedInstance] decode:data];
        if (binaryType == T_COMPOSITE_LIST) {
            oc_parameter = decode_data;
        } else if (decode_data) {
            oc_parameter = @[decode_data];
        }
    }
    MethodData* methodData = [[MethodData alloc] initMethodWithName:methodName parameter:oc_parameter.copy];
    return [bridgePlugin jsCallMethodBinarySync:methodData];
}

- (void)platformSendMethodResultBinaryInner:(NSString*)bridgeName
                            methodName:(NSString*)methodName
                            errorCode:(int)errorCode
                            errorMessage:(NSString*)errorMessage
                            result:(id)result {
    if (!bridgeName.length) {
        LOGE("bridgeName is null");
        return;
    }

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_methodName = [methodName UTF8String];
    NSData* dataResult = [[BridgeBinaryCodec sharedInstance] encode:result];

    std::string c_errorMessage;
    if (errorMessage) {
        c_errorMessage = [errorMessage UTF8String];
    }
    auto c_result = NSDataToBufferMapping(dataResult);
    OHOS::Ace::Platform::BridgeManager::PlatformSendMethodResultBinary(
        c_bridgeName, c_methodName, errorCode, c_errorMessage, std::move(c_result));
}

- (void)platformSendMessageBinaryInner:(NSString*)bridgeName data:(id)data {
    if (!bridgeName.length) {
        LOGE("bridgeName is null");
        return;
    }

    std::string c_bridgeName = [bridgeName UTF8String];
    NSData* dataResult = [[BridgeBinaryCodec sharedInstance] encode:data];
        auto c_data = NSDataToBufferMapping(dataResult);
        OHOS::Ace::Platform::BridgeManager::PlatformSendMessageBinary(c_bridgeName, std::move(c_data));
}

- (void)platformCallMethodBinaryInner:(NSString*)bridgeName
                                methodName:(NSString*)methodName
                                    param:(NSArray* _Nullable)params
                                reultValueCallback:(void (^)(ResultValue* _Nullable reultValue))callback {
    ResultValue* resultValue = [[ResultValue alloc] init];
    if (!bridgeName.length) {
        resultValue.errorCode = BRIDGE_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_NAME_ERROR_MESSAGE;
        if (callback) {
            callback(resultValue);
        }
        return;
    }

    if (!methodName.length) {
        resultValue.errorCode = BRIDGE_METHOD_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_METHOD_NAME_ERROR_MESSAGE;
        if (callback) {
            callback(resultValue);
        }
        return;
    }

    NSData* dataResult;
    if (params.count == 0) {
        dataResult = nil;
    } else {
        // T_COMPOSITE_LIST
        dataResult = [[BridgeBinaryCodec sharedInstance] encode:params];
    }

    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_methodName = [methodName UTF8String];
    auto c_result = NSDataToBufferMapping(dataResult);
    OHOS::Ace::Platform::BridgeManager::PlatformCallMethodBinary(
                c_bridgeName, c_methodName, std::move(c_result));
}

- (ResultValue*)platformCallMethodBinaryInnerResult:(NSString*)bridgeName
                                         methodName:(NSString*)methodName
                                              param:(NSArray* _Nullable)params {
    ResultValue* resultValue = [[ResultValue alloc] init];
    if (!bridgeName.length) {
        resultValue.errorCode = BRIDGE_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_NAME_ERROR_MESSAGE;
        return resultValue;
    }
    if (!methodName.length) {
        resultValue.errorCode = BRIDGE_METHOD_NAME_ERROR;
        resultValue.errorMessage = BRIDGE_METHOD_NAME_ERROR_MESSAGE;
        return resultValue;
    }
    NSData* dataResult = nil;
    if (params.count == 0) {
        dataResult = nil;
    } else {
        dataResult = [[BridgeBinaryCodec sharedInstance] encode:params];
    }
    std::string c_bridgeName = [bridgeName UTF8String];
    std::string c_methodName = [methodName UTF8String];
    auto c_result = NSDataToBufferMapping(dataResult);
    int32_t errorCode = BRIDGE_ERROR_NO;
    std::unique_ptr<OHOS::Ace::Platform::BufferMapping> data_bufferMapping =
        OHOS::Ace::Platform::BridgeManager::PlatformCallMethodBinarySync(
            c_bridgeName, c_methodName, std::move(c_result), errorCode);
    if (errorCode != BRIDGE_ERROR_NO) {
        resultValue.errorCode = SafeIntToErrorCode(static_cast<int>(errorCode));
        resultValue.errorMessage = [self getErrorMessage:errorCode];
        return resultValue;
    }
    NSData* nsData = ConvertBufferMappingToNSData(std::move(data_bufferMapping));
    if (nsData == nil && params.count != 0) {
        resultValue.errorCode = BRIDGE_DATA_ERROR;
        resultValue.errorMessage = BRIDGE_DATA_ERROR_MESSAGE;
        return resultValue;
    }
    id oc_resultValue = [[BridgeBinaryCodec sharedInstance] decode:nsData];
    resultValue.result = oc_resultValue ?: @"";
    resultValue.errorCode = BRIDGE_ERROR_NO;
    resultValue.errorMessage = BRIDGE_ERROR_NO_MESSAGE;
    resultValue.methodName = methodName;
    return resultValue;
}

ErrorCode SafeIntToErrorCode(int value) {
    if (value < BRIDGE_ERROR_NO || value > BRIDGE_END) {
        return BRIDGE_END;
    }
    return static_cast<ErrorCode>(value);
}

- (NSString*)getErrorMessage:(int32_t)index
{
    NSArray* arr = @[
        BRIDGE_ERROR_NO_MESSAGE, BRIDGE_NAME_ERROR_MESSAGE, BRIDGE_CREATE_ERROR_MESSAGE, BRIDGE_INVALID_MESSAGE,
        BRIDGE_METHOD_NAME_ERROR_MESSAGE, BRIDGE_METHOD_RUNNING_MESSAGE, BRIDGE_METHOD_UNIMPL_MESSAGE,
        BRIDGE_METHOD_PARAM_ERROR_MESSAGE, BRIDGE_METHOD_EXISTS_MESSAGE, BRIDGE_DATA_ERROR_MESSAGE,
        BRIDGE_BOTTOM_COMMUNICATION_ERROR_MESSAGE, BRIDGE_CODEC_TYPE_MISMATCH_MESSAGE,
        BRIDGE_CODEC_INVALID_MESSAGE, BRIDGE_END_MESSAGE
    ];
    if (index < 0 || index >= arr.count) {
        return @"";
    }
    return arr[index];
}

- (void)jsSendMethodResultBinaryInner:(NSString*)bridgeName
                    methodName:(NSString*)methodName
                    errorCode:(int)errorCode
                    errorMessage:(NSString*)errorMessage
                    result:(id)result {
    BridgePlugin* bridgePlugin = (BridgePlugin*)[self getPluginWithBridgeName:bridgeName];
    if (!bridgePlugin) {
        LOGE("bridgePlugin is null");
        return;
    }
    if (bridgePlugin.type != BINARY_TYPE) {
        LOGE("bridgePlugin type not BINARY_TYPE");
        return;
    }
    id oc_resultValue = [[BridgeBinaryCodec sharedInstance] decode:(NSData*)result];

    ResultValue* resultValue = [[ResultValue alloc] init];
    resultValue.result = oc_resultValue ?: @"";
    resultValue.errorCode = (ErrorCode)errorCode;
    resultValue.errorMessage = errorMessage ?: @"";
    resultValue.methodName = methodName;
    [bridgePlugin jsSendMethodResult:resultValue];
}

- (BridgePlugin* _Nullable)getPluginWithBridgeName:(NSString*)bridgeName {
    if (!bridgeName.length) {
        LOGE("bridgeName is null");
        return nil;
    }
    @synchronized(self) {
        BridgePlugin* bridgePlugin = (BridgePlugin*)[self.bridgeMap objectForKey:bridgeName];
        return bridgePlugin;
    }
}

- (void)dispatchTaskInQueueHandlerWithTaskInfo:(BridgeTaskInfo*)taskInfo {
    if (!taskInfo) {
        return;
    }
    NSString* bridgeName = taskInfo.bridgeName;
    if (!bridgeName || bridgeName.length == 0) {
        LOGE("no register bridge handler, %{public}s", bridgeName.UTF8String);
        return;
    }
    BridgeTaskQueueHandler* handler = (BridgeTaskQueueHandler*)[self.bridgeQueueMap objectForKey: bridgeName];
    if (!handler || !handler.isUseTaskQueue) {
        taskInfo.handler();
        return;
    }
    [handler dispatchTaskInfo:taskInfo];
}


@end