//
//  ExtSdkChatManagerWrapper.m
//
//
//  Created by 杜洁鹏 on 2019/10/8.
//

#import "ExtSdkChatManagerWrapper.h"
#import "ExtSdkMethodTypeObjc.h"

#import "ExtSdkToJson.h"

@interface ExtSdkChatManagerWrapper () <EMChatManagerDelegate, EMConversationDelegate>

@end

@implementation ExtSdkChatManagerWrapper

+ (nonnull instancetype)getInstance {
    static ExtSdkChatManagerWrapper *instance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
      instance = [[ExtSdkChatManagerWrapper alloc] init];
    });
    return instance;
}

- (void)initSdk {
    [EMClient.sharedClient.chatManager removeDelegate:self];
    [EMClient.sharedClient.chatManager addDelegate:self delegateQueue:nil];
    [EMClient.sharedClient.chatManager removeConversationDelegate:self];
    [EMClient.sharedClient.chatManager addConversationDelegate:self delegateQueue:nil];
}

#pragma mark - Actions

- (void)sendMessage:(NSDictionary *)param
     withMethodType:(NSString *)aChannelName
             result:(nonnull id<ExtSdkCallbackObjc>)result {

    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    [EMClient.sharedClient.chatManager sendMessage:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)resendMessage:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {

    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    [EMClient.sharedClient.chatManager sendMessage:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)recallMessage:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msg_id"];
    NSString *ext = param[@"ext"];
    EMChatMessage *msg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msgId];
    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }
    [EMClient.sharedClient.chatManager recallMessageWithMessageId:msgId
                                                              ext:ext
                                                       completion:^(EMError *aError) {
                                                         [weakSelf onResult:result
                                                             withMethodType:aChannelName
                                                                  withError:aError
                                                                 withParams:@(!aError)];
                                                       }];
}

- (void)getMessageWithMessageId:(NSDictionary *)param
                 withMethodType:(NSString *)aChannelName
                         result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *msgId = param[@"msg_id"];
    EMChatMessage *msg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msgId];
    if ([self getMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }
    [self onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)getConversationApi:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    EMConversation *conv = [self getConversation:param];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[conv toJsonObject]];
}

- (void)getMessageCount:(NSDictionary *)param
         withMethodType:(NSString *)aChannelName
                 result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager getMessageCountWithCompletion:^(NSInteger count, EMError *_Nullable aError) {
      [weakSelf onResult:result withMethodType:aChannelName withError:aError withParams:@(count)];
    }];
}

- (void)getUnreadMessageCount:(NSDictionary *)param
               withMethodType:(NSString *)aChannelName
                       result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSInteger unreadCount = 0;
    EMError *error = nil;
    unreadCount = [EMClient.sharedClient.chatManager getUnreadMessageCount];
    [weakSelf onResult:result withMethodType:aChannelName withError:error withParams:@(unreadCount)];
}

- (void)updateChatMessage:(NSDictionary *)param
           withMethodType:(NSString *)aChannelName
                   result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];
    EMChatMessage *dbMsg = [EMClient.sharedClient.chatManager getMessageWithMessageId:param[@"message"][@"msgId"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }
    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:dbMsg]) {
        return;
    }

    [self mergeMessage:msg withDBMessage:dbMsg];

    [EMClient.sharedClient.chatManager updateMessage:dbMsg
                                          completion:^(EMChatMessage *aMessage, EMError *aError) {
                                            [weakSelf onResult:result
                                                withMethodType:aChannelName
                                                     withError:aError
                                                    withParams:[aMessage toJsonObject]];
                                          }];
}

- (void)importMessages:(NSDictionary *)param
        withMethodType:(NSString *)aChannelName
                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray *dictAry = param[@"messages"];
    NSMutableArray *messages = [NSMutableArray array];
    for (NSDictionary *dict in dictAry) {
        [messages addObject:[EMChatMessage fromJsonObject:dict]];
    }
    [[EMClient sharedClient].chatManager importMessages:messages
                                             completion:^(EMError *aError) {
                                               [weakSelf onResult:result
                                                   withMethodType:aChannelName
                                                        withError:aError
                                                       withParams:@(!aError)];
                                             }];
}

- (void)downloadAttachmentInCombine:(NSDictionary *)param
                     withMethodType:(NSString *)aChannelName
                             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    [EMClient.sharedClient.chatManager downloadMessageAttachment:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)downloadThumbnailInCombine:(NSDictionary *)param
                    withMethodType:(NSString *)aChannelName
                            result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    [EMClient.sharedClient.chatManager downloadMessageThumbnail:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)downloadAttachment:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    EMChatMessage *needDownMSg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msg.messageId];
    [EMClient.sharedClient.chatManager downloadMessageAttachment:needDownMSg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)downloadThumbnail:(NSDictionary *)param
           withMethodType:(NSString *)aChannelName
                   result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    EMChatMessage *needDownMSg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msg.messageId];
    [EMClient.sharedClient.chatManager downloadMessageThumbnail:needDownMSg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)downloadBigImage:(NSDictionary *)param
          withMethodType:(NSString *)aChannelName
                  result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    __block EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    EMChatMessage *needDownMSg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msg.messageId];
    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:needDownMSg]) {
        return;
    }

    [EMClient.sharedClient.chatManager downloadBigImageAttachment:needDownMSg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(EMChatMessage *message, EMError *error) {
          if (error) {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"error" : [error toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"message" : [message toJsonObject],
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageError
                       }];
          } else {
              [weakSelf onReceive:aChannelName
                       withParams:@{
                           @"message" : [message toJsonObject],
                           @"localTime" : @(msg.localTime),
                           @"msgId" : msg.messageId,
                           @"callbackType" : ExtSdkMethodKeyOnMessageSuccess
                       }];
          }
        }];

    [weakSelf onResult:result withMethodType:aChannelName withError:nil withParams:[msg toJsonObject]];
}

- (void)voiceMessageToText:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    EMChatMessage *dbMsg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msg.messageId];
    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:dbMsg]) {
        return;
    }

    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager voiceMessageToText:dbMsg
                                               completion:^(NSString *text, EMError *error) {
                                                 [weakSelf onResult:result
                                                     withMethodType:aChannelName
                                                          withError:error
                                                         withParams:@{@"text" : text ?: @""}];
                                               }];
}

- (void)voiceFileToText:(NSDictionary *)param
         withMethodType:(NSString *)aChannelName
                 result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *filePath = param[@"filePath"];
    NSDictionary *voiceParamJson = param[@"voiceParam"];
    EMVoiceParam *voiceParam = nil;
    if ([voiceParamJson isKindOfClass:[NSDictionary class]]) {
        voiceParam = [[EMVoiceParam alloc] init];
        NSString *format = voiceParamJson[@"format"];
        if ([format isEqualToString:@"amr"]) {
            voiceParam.format = EMVoiceFormatAMR;
        } else if ([format isEqualToString:@"mp3"]) {
            voiceParam.format = EMVoiceFormatMP3;
        } else {
            voiceParam.format = EMVoiceFormatPCM;
        }
        if (voiceParamJson[@"sampleRate"]) { voiceParam.sampleRate = [voiceParamJson[@"sampleRate"] integerValue]; }
        if (voiceParamJson[@"bitsPerSample"]) { voiceParam.bitsPerSample = [voiceParamJson[@"bitsPerSample"] integerValue]; }
        if (voiceParamJson[@"channels"]) { voiceParam.channels = [voiceParamJson[@"channels"] integerValue]; }
    }

    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager voiceFileToText:filePath
                                            voiceParam:voiceParam
                                            completion:^(NSString *text, EMError *error) {
                                              [weakSelf onResult:result
                                                  withMethodType:aChannelName
                                                       withError:error
                                                      withParams:@{@"text" : text ?: @""}];
                                            }];
}

- (void)loadAllConversations:(NSDictionary *)param
              withMethodType:(NSString *)aChannelName
                      result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSArray *conversations = [EMClient.sharedClient.chatManager getAllConversations];
    NSArray *sortedList =
        [conversations sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
          if (((EMConversation *)obj1).latestMessage.timestamp > ((EMConversation *)obj2).latestMessage.timestamp) {
              return NSOrderedAscending;
          } else {
              return NSOrderedDescending;
          }
        }];
    NSMutableArray *conList = [NSMutableArray array];
    for (EMConversation *conversation in sortedList) {
        [conList addObject:[conversation toJsonObject]];
    }

    [self onResult:result withMethodType:aChannelName withError:nil withParams:conList];
}

- (void)deleteConversation:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *conversationId = param[@"convId"];
    BOOL isDeleteMsgs = [param[@"deleteMessages"] boolValue];
    [EMClient.sharedClient.chatManager deleteConversation:conversationId
                                         isDeleteMessages:isDeleteMsgs
                                               completion:^(NSString *aConversationId, EMError *aError) {
                                                 [weakSelf onResult:result
                                                     withMethodType:aChannelName
                                                          withError:aError
                                                         withParams:@(!aError)];
                                               }];
}

- (void)deleteConversations:(NSDictionary *)param
             withMethodType:(NSString *)aChannelName
                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray *convIds = param[@"convIds"];
    BOOL isDeleteMsgs = [param[@"deleteMessages"] boolValue];
    NSMutableArray *conversations = [NSMutableArray array];
    for (NSString *convId in convIds) {
        EMConversation *conversation =
            [EMClient.sharedClient.chatManager getConversationWithConvId:convId];
        if (conversation) {
            [conversations addObject:conversation];
        }
    }
    if (convIds.count > 0 && conversations.count == 0) {
        // Conversation IDs that do not exist are skipped, aligning with Android.
        [weakSelf onResult:result
            withMethodType:aChannelName
                 withError:nil
                withParams:@(YES)];
        return;
    }
    [EMClient.sharedClient.chatManager
        deleteConversations:conversations
           isDeleteMessages:isDeleteMsgs
                 completion:^(EMError *aError) {
                   [weakSelf onResult:result
                       withMethodType:aChannelName
                            withError:aError
                           withParams:@(!aError)];
                 }];
}

- (void)fetchGroupMessageReadReceipts:(NSDictionary *)param
                       withMethodType:(NSString *)aChannelName
                               result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *msgId = param[@"msg_id"];
    int pageSize = [param[@"pageSize"] intValue];
    NSString *receiptId = param[@"receipt_id"];
    NSString *groupId = param[@"group_id"];

    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager
        asyncFetchGroupMessageReadUsersFromServer:msgId
                                          groupId:groupId
                                    readReceiptId:receiptId
                                         pageSize:pageSize
                                       completion:^(EMCursorResult *aResult, EMError *aError, int totalCount) {
                                         NSMutableDictionary *data =
                                             [[aResult toJsonObject] mutableCopy] ?: [NSMutableDictionary dictionary];
                                         data[@"totalCount"] = @(totalCount);
                                         [weakSelf onResult:result
                                             withMethodType:aChannelName
                                                  withError:aError
                                                 withParams:data];
                                       }];
}

- (void)sendMessageReadReceipts:(NSDictionary *)param
                 withMethodType:(NSString *)aChannelName
                        result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray<NSString *> *msgIds = param[@"msg_ids"];
    NSMutableArray<EMChatMessage *> *messages = [NSMutableArray array];
    for (NSString *msgId in msgIds) {
        EMChatMessage *msg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msgId];
        if (msg) {
            [messages addObject:msg];
        }
    }
    [EMClient.sharedClient.chatManager sendMessageReadReceipts:messages
                                                    completion:^(EMError *aError) {
                                                      [weakSelf onResult:result
                                                          withMethodType:aChannelName
                                                               withError:aError
                                                              withParams:nil];
                                                    }];
}

- (void)clearConversationUnreadMessageCount:(NSDictionary *)param
                             withMethodType:(NSString *)aChannelName
                                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *conversationId = param[@"convId"];
    [EMClient.sharedClient.chatManager clearConversationUnreadMessageCount:conversationId
                                                                completion:^(EMError *aError) {
                                                                  [weakSelf onResult:result
                                                                      withMethodType:aChannelName
                                                                           withError:aError
                                                                          withParams:nil];
                                                                }];
}

- (void)clearAllConversationUnreadMessageCount:(NSDictionary *)param
                                withMethodType:(NSString *)aChannelName
                                        result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager clearAllConversationUnreadMessageCount:^(EMError *aError) {
      [weakSelf onResult:result withMethodType:aChannelName withError:aError withParams:nil];
    }];
}

- (void)getGroupMessageReadReceipts:(NSDictionary *)param
                     withMethodType:(NSString *)aChannelName
                             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray<NSString *> *msgIds = param[@"msg_ids"];
    NSMutableArray<EMChatMessage *> *messages = [NSMutableArray array];
    for (NSString *msgId in msgIds) {
        EMChatMessage *msg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msgId];
        if (msg) {
            [messages addObject:msg];
        }
    }
    [EMClient.sharedClient.chatManager
        getGroupMessageReadReceipts:messages
                         completion:^(NSArray<EMMessageReadReceipt *> *_Nullable aReceipts, EMError *_Nullable aError) {
                           NSMutableArray *list = [NSMutableArray array];
                           for (EMMessageReadReceipt *receipt in aReceipts) {
                               [list addObject:[receipt toJsonObject]];
                           }
                           [weakSelf onResult:result
                               withMethodType:aChannelName
                                    withError:aError
                                   withParams:aError ? nil : list];
                         }];
}

- (void)searchChatMsgFromDB:(NSDictionary *)param
             withMethodType:(NSString *)aChannelName
                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *keywords = param[@"keywords"];
    long long timestamp = [param[@"timestamp"] longLongValue];
    int maxCount = [param[@"maxCount"] intValue];
    NSString *from = param[@"from"];
    EMMessageSearchDirection direction = [ExtSdkConvertHelper searchDirectionFromString:param[@"direction"]];
    EMMessageSearchScope scope = [ExtSdkConvertHelper searchScopeFromInt:[param[@"searchScope"] integerValue]];
    [EMClient.sharedClient.chatManager loadMessagesWithKeyword:keywords
                                                     timestamp:timestamp
                                                         count:maxCount
                                                      fromUser:from
                                               searchDirection:direction
                                                         scope:scope
                                                    completion:^(NSArray<EMChatMessage *> *aMessages, EMError *aError) {
                                                      NSMutableArray *msgList = [NSMutableArray array];
                                                      for (EMChatMessage *msg in aMessages) {
                                                          [msgList addObject:[msg toJsonObject]];
                                                      }

                                                      [weakSelf onResult:result
                                                          withMethodType:aChannelName
                                                               withError:aError
                                                              withParams:msgList];
                                                    }];
}

- (void)deleteRemoteConversation:(NSDictionary *)param
                  withMethodType:(NSString *)aChannelName
                          result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *conversationId = param[@"conversationId"];
    EMConversationType type = EMConversationTypeChat;
    BOOL isDeleteRemoteMessage = [param[@"isDeleteRemoteMessage"] boolValue];
    int intType = [param[@"conversationType"] intValue];
    if (intType == 0) {
        type = EMConversationTypeChat;
    } else if (intType == 1) {
        type = EMConversationTypeGroupChat;
    } else {
        type = EMConversationTypeChatRoom;
    }

    [EMClient.sharedClient.chatManager deleteServerConversation:conversationId
                                               conversationType:type
                                         isDeleteServerMessages:isDeleteRemoteMessage
                                                     completion:^(NSString *aConversationId, EMError *aError) {
                                                       [weakSelf onResult:result
                                                           withMethodType:aChannelName
                                                                withError:aError
                                                               withParams:@(!aError)];
                                                     }];
}

- (void)translateMessage:(NSDictionary *)param
          withMethodType:(NSString *)aChannelName
                  result:(nonnull id<ExtSdkCallbackObjc>)result {
    EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];
    NSArray *languages = param[@"languages"];

    EMChatMessage *dbMsg = [EMClient.sharedClient.chatManager getMessageWithMessageId:msg.messageId];

    if ([self checkMessageParams:result withMethodType:aChannelName withMessage:msg]) {
        return;
    }

    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager translateMessage:dbMsg
                                        targetLanguages:languages
                                             completion:^(EMChatMessage *message, EMError *error) {
                                               [weakSelf onResult:result
                                                   withMethodType:aChannelName
                                                        withError:error
                                                       withParams:@{@"message" : [message toJsonObject]}];
                                             }];
}

- (void)fetchSupportLanguages:(NSDictionary *)param
               withMethodType:(NSString *)aChannelName
                       result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager
        fetchSupportedLanguages:^(NSArray<EMTranslateLanguage *> *_Nullable languages, EMError *_Nullable error) {
          [weakSelf onResult:result withMethodType:aChannelName withError:error withParams:[languages toJsonArray]];
        }];
}

- (void)addReaction:(NSDictionary *)param
     withMethodType:(NSString *)aChannelName
             result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *reaction = param[@"reaction"];
    NSString *msgId = param[@"msgId"];
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager addReaction:reaction
                                         toMessage:msgId
                                        completion:^(EMError *error) {
                                          [weakSelf onResult:result
                                              withMethodType:aChannelName
                                                   withError:error
                                                  withParams:nil];
                                        }];
}

- (void)removeReaction:(NSDictionary *)param
        withMethodType:(NSString *)aChannelName
                result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *reaction = param[@"reaction"];
    NSString *msgId = param[@"msgId"];
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager removeReaction:reaction
                                          fromMessage:msgId
                                           completion:^(EMError *error) {
                                             [weakSelf onResult:result
                                                 withMethodType:aChannelName
                                                      withError:error
                                                     withParams:nil];
                                           }];
}

- (void)fetchReactionList:(NSDictionary *)param
           withMethodType:(NSString *)aChannelName
                   result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSArray *msgIds = param[@"msgIds"];
    NSString *groupId = param[@"groupId"];
    EMChatType type = [ExtSdkConvertHelper chatTypeFromInt:[param[@"chatType"] intValue]];
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager getReactionList:msgIds
                                               groupId:groupId
                                              chatType:type
                                            completion:^(NSDictionary<NSString *, NSArray *> *dic, EMError *error) {
                                              NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
                                              for (NSString *key in dic.allKeys) {
                                                  NSArray *ary = dic[key];
                                                  NSMutableArray *list = [NSMutableArray array];
                                                  for (EMMessageReaction *reaction in ary) {
                                                      [list addObject:[reaction toJsonObject]];
                                                  }
                                                  dictionary[key] = list;
                                              }

                                              [weakSelf onResult:result
                                                  withMethodType:aChannelName
                                                       withError:error
                                                      withParams:dictionary];
                                            }];
}

- (void)fetchReactionDetail:(NSDictionary *)param
             withMethodType:(NSString *)aChannelName
                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *msgId = param[@"msgId"];
    NSString *reaction = param[@"reaction"];
    NSString *cursor = param[@"cursor"];
    int pageSize = 50;
    if (param[@"pageSize"] != nil) {
        pageSize = [param[@"pageSize"] intValue];
    }
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager
        getReactionDetail:msgId
                 reaction:reaction
                   cursor:cursor
                 pageSize:pageSize
               completion:^(EMMessageReaction *reaction, NSString *_Nullable cursor, EMError *error) {
                 EMCursorResult *cursorResult = nil;
                 if (error == nil) {
                     cursorResult = [EMCursorResult cursorResultWithList:@[ reaction ] andCursor:cursor];
                 }

                 [weakSelf onResult:result
                     withMethodType:aChannelName
                          withError:error
                         withParams:[cursorResult toJsonObject]];
               }];
}

- (void)deleteMessagesBeforeTimestamp:(NSDictionary *)param
                       withMethodType:(NSString *)aChannelName
                               result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSUInteger timestamp = [param[@"timestamp"] longValue];
    __weak typeof(self) weakSelf = self;
    [EMClient.sharedClient.chatManager deleteMessagesBefore:timestamp
                                                 completion:^(EMError *error) {
                                                   [weakSelf onResult:result
                                                       withMethodType:aChannelName
                                                            withError:error
                                                           withParams:nil];
                                                 }];
}

- (void)removeMessagesFromServerWithMsgIds:(NSDictionary *)param
                            withMethodType:(NSString *)aChannelName
                                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *convId = param[@"convId"];
    EMConversationType type = [ExtSdkConvertHelper conversationTypeFromInt:[param[@"convType"] intValue]];
    EMConversation *conversation = [self getConversation:param];
    NSArray *msgIds = param[@"msgIds"];
    [conversation removeMessagesFromServerMessageIds:msgIds
                                          completion:^(EMError *_Nullable aError) {
                                            [weakSelf onResult:result
                                                withMethodType:aChannelName
                                                     withError:aError
                                                    withParams:nil];
                                          }];
}

- (void)removeMessagesFromServerWithTs:(NSDictionary *)param
                        withMethodType:(NSString *)aChannelName
                                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *convId = param[@"convId"];
    EMConversationType type = [ExtSdkConvertHelper conversationTypeFromInt:[param[@"convType"] intValue]];
    long timestamp = [param[@"timestamp"] longValue];
    EMConversation *conversation = [self getConversation:param];
    [conversation removeMessagesFromServerWithTimeStamp:timestamp
                                             completion:^(EMError *_Nullable aError) {
                                               [weakSelf onResult:result
                                                   withMethodType:aChannelName
                                                        withError:aError
                                                       withParams:nil];
                                             }];
}

- (void)fetchHistoryMessagesByOptions:(NSDictionary *)param
                       withMethodType:(NSString *)aChannelName
                               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *convId = param[@"convId"];
    EMConversationType type = [ExtSdkConvertHelper conversationTypeFromInt:[param[@"convType"] intValue]];
    NSString *cursor = param[@"cursor"];
    int pageSize = [param[@"pageSize"] intValue];
    EMFetchServerMessagesOption *option = [EMFetchServerMessagesOption fromJsonObject:param[@"options"]];

    [EMClient.sharedClient.chatManager
        fetchMessagesFromServerBy:convId
                 conversationType:type
                           cursor:cursor
                         pageSize:pageSize
                           option:option
                       completion:^(EMCursorResult<EMChatMessage *> *_Nullable data, EMError *_Nullable aError) {
                         [weakSelf onResult:result
                             withMethodType:aChannelName
                                  withError:aError
                                 withParams:[data toJsonObject]];
                       }];
}

- (void)pinConversation:(NSDictionary *)param
         withMethodType:(NSString *)aChannelName
                 result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *convId = param[@"convId"];
    BOOL isPinned = [param[@"isPinned"] boolValue];
    [EMClient.sharedClient.chatManager pinConversation:convId
                                              isPinned:isPinned
                                       completionBlock:^(EMError *_Nullable error) {
                                         [weakSelf onResult:result
                                             withMethodType:aChannelName
                                                  withError:error
                                                 withParams:nil];
                                       }];
}

- (void)downloadAndParseCombineMessage:(NSDictionary *)param
                        withMethodType:(NSString *)aChannelName
                                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    EMChatMessage *msg = [EMChatMessage fromJsonObject:param[@"message"]];
    [EMClient.sharedClient.chatManager
        downloadAndParseCombineMessage:msg
                            completion:^(NSArray<EMChatMessage *> *_Nullable messages, EMError *_Nullable error) {
                              NSMutableArray *msgJsonAry = [NSMutableArray array];
                              for (EMChatMessage *msg in messages) {
                                  [msgJsonAry addObject:[msg toJsonObject]];
                              }
                              [weakSelf onResult:result
                                  withMethodType:aChannelName
                                       withError:error
                                      withParams:msgJsonAry];
                            }];
}

- (void)addRemoteAndLocalConversationsMark:(NSDictionary *)param
                            withMethodType:(NSString *)aChannelName
                                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray *conversationIds = param[@"convIds"];
    EMMarkType mark = (EMMarkType)[param[@"mark"] integerValue];
    [EMClient.sharedClient.chatManager addConversationMark:conversationIds
                                                      mark:mark
                                                completion:^(EMError *_Nullable aError) {
                                                  [weakSelf onResult:result
                                                      withMethodType:aChannelName
                                                           withError:aError
                                                          withParams:nil];
                                                }];
}

- (void)deleteRemoteAndLocalConversationsMark:(NSDictionary *)param
                               withMethodType:(NSString *)aChannelName
                                       result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray *conversationIds = param[@"convIds"];
    EMMarkType mark = (EMMarkType)[param[@"mark"] integerValue];
    [EMClient.sharedClient.chatManager removeConversationMark:conversationIds
                                                         mark:mark
                                                   completion:^(EMError *_Nullable aError) {
                                                     [weakSelf onResult:result
                                                         withMethodType:aChannelName
                                                              withError:aError
                                                             withParams:nil];
                                                   }];
}

- (void)deleteAllMessageAndConversation:(NSDictionary *)param
                         withMethodType:(NSString *)aChannelName
                                 result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    BOOL clearServerData = [param[@"clearServerData"] boolValue];
    [EMClient.sharedClient.chatManager deleteAllMessagesAndConversations:clearServerData
                                                              completion:^(EMError *_Nullable aError) {
                                                                [weakSelf onResult:result
                                                                    withMethodType:aChannelName
                                                                         withError:aError
                                                                        withParams:nil];
                                                              }];
}

- (void)pinMessage:(NSDictionary *)param
    withMethodType:(NSString *)aChannelName
            result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msgId"];
    [EMClient.sharedClient.chatManager pinMessage:msgId
                                       completion:^(EMChatMessage *_Nullable message, EMError *_Nullable aError) {
                                         [weakSelf onResult:result
                                             withMethodType:aChannelName
                                                  withError:aError
                                                 withParams:nil];
                                       }];
}

- (void)unpinMessage:(NSDictionary *)param
      withMethodType:(NSString *)aChannelName
              result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msgId"];
    [EMClient.sharedClient.chatManager unpinMessage:msgId
                                         completion:^(EMChatMessage *_Nullable message, EMError *_Nullable aError) {
                                           [weakSelf onResult:result
                                               withMethodType:aChannelName
                                                    withError:aError
                                                   withParams:nil];
                                         }];
}

- (void)fetchPinnedMessages:(NSDictionary *)param
             withMethodType:(NSString *)aChannelName
                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *conversationId = param[@"convId"];
    [EMClient.sharedClient.chatManager
        getPinnedMessagesFromServer:conversationId
                         completion:^(NSArray<EMChatMessage *> *_Nullable messages, EMError *_Nullable aError) {
                           NSMutableArray *msgList = [NSMutableArray array];
                           for (EMChatMessage *msg in messages) {
                               [msgList addObject:[msg toJsonObject]];
                           }

                           [weakSelf onResult:result withMethodType:aChannelName withError:aError withParams:msgList];
                         }];
}

- (void)searchMessages:(NSDictionary *)param
        withMethodType:(NSString *)aChannelName
                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray *typesJson = param[@"types"];
    NSMutableArray<NSNumber *> *types = [NSMutableArray array];
    for (NSString *type in typesJson) {
        [types addObject:[NSNumber numberWithInteger:[ExtSdkConvertHelper messageBodyFromString:type]]];
    }
    long long timestamp = [param[@"timestamp"] longLongValue];
    int count = [param[@"count"] intValue];
    NSString *from = param[@"from"];
    EMMessageSearchDirection direction = [ExtSdkConvertHelper searchDirectionFromString:param[@"direction"]];
    [EMClient.sharedClient.chatManager
        searchMessagesWithTypes:types
                      timestamp:timestamp
                          count:count
                       fromUser:from
                searchDirection:direction
                     completion:^(NSArray<EMChatMessage *> *_Nullable aMessages, EMError *_Nullable aError) {
                       NSMutableArray *msgs = [NSMutableArray array];
                       if (aMessages) {
                           for (EMChatMessage *msg in aMessages) {
                               [msgs addObject:[msg toJsonObject]];
                           }
                       }
                       [weakSelf onResult:result withMethodType:aChannelName withError:aError withParams:msgs];
                     }];
}

- (void)searchMessagesFromServer:(NSDictionary *)param
                  withMethodType:(NSString *)aChannelName
                          result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray *keywordList = param[@"keywordList"];
    if (![keywordList isKindOfClass:[NSArray class]] || keywordList.count == 0) {
        EMError *error = [EMError errorWithDescription:@"searchMessagesFromServer: keywordList is required" code:1];
        [weakSelf onResult:result withMethodType:aChannelName withError:error withParams:nil];
        return;
    }
    EMMessageSearchOption *option = [[EMMessageSearchOption alloc] init];
    option.keywordList = keywordList;
    option.keywordMatchType = [param[@"keywordMatchType"] intValue] == 1 ? EMKeywordListMatchTypeAND : EMKeywordListMatchTypeOR;
    NSString *conversationId = param[@"conversationId"];
    if (conversationId.length > 0) {
        option.conversationId = conversationId;
    }
    NSArray *msgTypesJson = param[@"msgTypes"];
    if ([msgTypesJson isKindOfClass:[NSArray class]] && msgTypesJson.count > 0) {
        NSMutableArray<NSNumber *> *msgTypes = [NSMutableArray array];
        for (NSString *type in msgTypesJson) {
            [msgTypes addObject:[NSNumber numberWithInteger:[ExtSdkConvertHelper messageBodyFromString:type]]];
        }
        option.msgTypes = msgTypes;
    }
    if (param[@"startTime"]) { option.startTime = [param[@"startTime"] longLongValue]; }
    if (param[@"endTime"]) { option.endTime = [param[@"endTime"] longLongValue]; }
    if (param[@"searchScope"]) { option.searchScope = [ExtSdkConvertHelper searchScopeFromInt:[param[@"searchScope"] intValue]]; }
    NSInteger pageSize = [param[@"pageSize"] integerValue];
    NSInteger pageNum = [param[@"pageNum"] integerValue];
    [EMClient.sharedClient.chatManager
        searchMessagesFromServerWithOption:option
                                  pageSize:pageSize
                                   pageNum:pageNum
                                completion:^(EMPageResult<EMSearchServerMessageResult *> *_Nullable aResult,
                                             EMError *_Nullable aError) {
                                  [weakSelf onResult:result
                                      withMethodType:aChannelName
                                           withError:aError
                                          withParams:[aResult toJsonObject]];
                                }];
}

- (void)removeMessagesWithTimestamp:(NSDictionary *)param
                     withMethodType:(NSString *)aChannelName
                             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    EMConversation *conversation = [self getConversation:param];
    NSTimeInterval timestamp = [param[@"timestamp"] doubleValue];
    [conversation removeMessagesFromServerWithTimeStamp:timestamp
                                             completion:^(EMError *_Nullable aError) {
                                               [weakSelf onResult:result
                                                   withMethodType:aChannelName
                                                        withError:aError
                                                       withParams:nil];
                                             }];
}

- (void)getMessagesWithIds:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSArray<NSString *> *msgIds = param[@"msgIds"];
    NSString *convId = param[@"convId"];
    [EMClient.sharedClient.chatManager
               getMessages:msgIds
        withConversationId:convId
                completion:^(NSArray<EMChatMessage *> *_Nullable aMessages, EMError *_Nullable aError) {
                  NSMutableArray *msgs = [NSMutableArray array];
                  if (aMessages) {
                      for (EMChatMessage *msg in aMessages) {
                          [msgs addObject:[msg toJsonObject]];
                      }
                  }
                  [weakSelf onResult:result withMethodType:aChannelName withError:aError withParams:msgs];
                }];
}

- (void)getConvsMsgsWithKeyword:(NSDictionary *)param
                 withMethodType:(NSString *)aChannelName
                         result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *keywords = param[@"keywords"];
    long long timestamp = [param[@"timestamp"] longLongValue];
    NSString *from = param[@"from"];
    EMMessageSearchDirection direction = [ExtSdkConvertHelper searchDirectionFromString:param[@"direction"]];
    EMMessageSearchScope scope = [ExtSdkConvertHelper searchScopeFromInt:[param[@"searchScope"] intValue]];
    [EMClient.sharedClient.chatManager
        loadConversationMessagesWithKeyword:keywords
                                  timestamp:timestamp
                                   fromUser:from
                            searchDirection:direction
                                      scope:scope
                                 completion:^(
                                     NSDictionary<NSString *, NSArray<NSString *> *> *_Nullable aConversationMessages,
                                     EMError *_Nullable aError) {
                                   NSMutableArray *convs = [NSMutableArray array];
                                   if (aConversationMessages) {
                                       for (NSString *convId in aConversationMessages) {
                                           [convs addObject:@{
                                               @"convId" : convId,
                                               @"msgIds" : aConversationMessages[convId]
                                           }];
                                       }
                                   }
                                   NSMutableArray *msgs = [NSMutableArray array];
                                   [weakSelf onResult:result
                                       withMethodType:aChannelName
                                            withError:aError
                                           withParams:convs];
                                 }];
}

- (void)modifyMsgBody:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msgId"];
    EMMessageBody *body = [EMMessageBody fromJsonObject:param[@"body"]];
    NSDictionary *ext = param[@"ext"];
    [EMClient.sharedClient.chatManager modifyMessage:msgId
                                                body:body
                                                 ext:ext
                                          completion:^(EMError *_Nullable error, EMChatMessage *_Nullable message) {
                                            [weakSelf onResult:result
                                                withMethodType:aChannelName
                                                     withError:error
                                                    withParams:[message toJsonObject]];
                                          }];
}

#pragma mark - EMConversationDelegate

- (void)conversationListDidUpdate:(NSArray *)aConversationList {
    [self onReceive:ExtSdkMethodKeyOnConversationUpdate withParams:nil];
}

#pragma mark - EMChatManagerDelegate

- (void)messagesDidReceive:(NSArray *)aMessages {
    NSMutableArray *msgList = [NSMutableArray array];
    for (EMChatMessage *msg in aMessages) {
        [msgList addObject:[msg toJsonObject]];
    }
    [self onReceive:ExtSdkMethodKeyOnMessagesReceived withParams:msgList];
}

- (void)onStreamMessagesReceived:(NSArray<EMChatMessage *> * _Nonnull)messages {
  NSMutableArray *msgList = [NSMutableArray array];
  for (EMChatMessage *msg in messages) {
      [msgList addObject:[msg toJsonObject]];
  }
  [self onReceive:ExtSdkMethodKeyOnStreamMessagesReceived withParams:msgList];
}

- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
    NSMutableArray *cmdMsgList = [NSMutableArray array];
    for (EMChatMessage *msg in aCmdMessages) {
        [cmdMsgList addObject:[msg toJsonObject]];
    }

    [self onReceive:ExtSdkMethodKeyOnCmdMessagesReceived withParams:cmdMsgList];
}

- (void)messagesDidDeliver:(NSArray *)aMessages {
    NSMutableArray *list = [NSMutableArray array];
    for (EMChatMessage *msg in aMessages) {
        NSDictionary *json = [msg toJsonObject];
        [list addObject:json];
    }

    [self onReceive:ExtSdkMethodKeyOnMessagesDelivered withParams:list];
}

- (void)messagesInfoDidRecall:(NSArray<EMRecallMessageInfo *> *)aRecallMessagesInfo {
    NSMutableArray *list = [NSMutableArray array];
    for (EMRecallMessageInfo *info in aRecallMessagesInfo) {
        NSDictionary *jsonObject = [info toJsonObject];
        if (jsonObject != nil) {
            [list addObject:jsonObject];
        }
    }

    [self onReceive:ExtSdkMethodKeyOnMessagesRecalledInfo withParams:list];
}

- (void)messageStatusDidChange:(EMChatMessage *)aMessage withError:(EMError *)aError {
}

// TODO: 安卓未找到对应回调
- (void)messageAttachmentStatusDidChange:(EMChatMessage *)aMessage withError:(EMError *)aError {
}

- (void)onMessageReadReceipts:(NSArray<EMMessageReadReceipt *> *_Nonnull)aReceipts {
    NSMutableArray *list = [NSMutableArray array];
    for (EMMessageReadReceipt *receipt in aReceipts) {
        [list addObject:[receipt toJsonObject]];
    }

    [self onReceive:ExtSdkMethodKeyOnMessageReadReceipts withParams:@{@"receipts" : list}];
}

- (void)messageReactionDidChange:(NSArray<EMMessageReactionChange *> *)changes {
    NSMutableArray *list = [NSMutableArray array];
    for (EMMessageReactionChange *change in changes) {
        [list addObject:[change toJsonObject]];
    }

    [self onReceive:ExtSdkMethodKeyChatOnMessageReactionDidChange withParams:list];
}

- (void)onMessageContentChanged:(EMChatMessage *_Nonnull)message
                     operatorId:(NSString *_Nonnull)operatorId
                  operationTime:(NSUInteger)operationTime {
    NSDictionary *dict = @{
        @"message" : [message toJsonObject],
        @"lastModifyOperatorId" : operatorId,
        @"lastModifyTime" : @(operationTime)
    };
    [self onReceive:ExtSdkMethodKeyOnMessageContentChanged withParams:dict];
}

- (void)onMessagePinChanged:(NSString *_Nonnull)messageId
             conversationId:(NSString *_Nonnull)conversationId
                  operation:(EMMessagePinOperation)pinOperation
                    pinInfo:(EMMessagePinInfo *_Nonnull)pinInfo {
    NSDictionary *dict = @{
        @"messageId" : messageId,
        @"conversationId" : conversationId,
        @"pinOperation" : @(pinOperation),
        @"pinInfo" : [pinInfo toJsonObject]
    };
    [self onReceive:ExtSdkMethodKeyonMessagePinChanged withParams:dict];
}

@end
