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

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

#import "ExtSdkToJson.h"

@interface ExtSdkChatManagerWrapper () <AgoraChatManagerDelegate>

@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 {
    [AgoraChatClient.sharedClient.chatManager removeDelegate:self];
    [AgoraChatClient.sharedClient.chatManager addDelegate:self delegateQueue:nil];
}

#pragma mark - Actions

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

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

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

    [AgoraChatClient.sharedClient.chatManager sendMessage:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(AgoraChatMessage *message, AgoraChatError *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 AgoraChatMessage *msg = [AgoraChatMessage fromJsonObject:param];

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

    [AgoraChatClient.sharedClient.chatManager resendMessage:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(AgoraChatMessage *message, AgoraChatError *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)ackMessageRead:(NSDictionary *)param
        withMethodType:(NSString *)aChannelName
                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msg_id"];
    NSString *to = param[@"to"];
    [AgoraChatClient.sharedClient.chatManager sendMessageReadAck:msgId
                                                   toUser:to
                                               completion:^(AgoraChatError *aError) {
                                                 [weakSelf onResult:result
                                                     withMethodType:aChannelName
                                                          withError:aError
                                                         withParams:@(!aError)];
                                               }];
}

- (void)ackGroupMessageRead:(NSDictionary *)param
             withMethodType:(NSString *)aChannelName
                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msg_id"];
    NSString *groupId = param[@"group_id"];
    NSString *content = param[@"content"];
    [AgoraChatClient.sharedClient.chatManager
        sendGroupMessageReadAck:msgId
                        toGroup:groupId
                        content:content
                     completion:^(AgoraChatError *aError) {
                       [weakSelf onResult:result
                           withMethodType:aChannelName
                                withError:aError
                               withParams:@(!aError)];
                     }];
}

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

- (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"];
    AgoraChatMessage *msg =
        [AgoraChatClient.sharedClient.chatManager getMessageWithMessageId:msgId];
    if ([self checkMessageParams:result
                  withMethodType:aChannelName
                     withMessage:msg]) {
        return;
    }
    [AgoraChatClient.sharedClient.chatManager
        recallMessageWithMessageId:msgId
                               ext:ext
                        completion:^(AgoraChatError *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"];
    AgoraChatMessage *msg =
        [AgoraChatClient.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;
    AgoraChatConversation *conv = [self getConversation:param];

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

- (void)markAllMessagesAsRead:(NSDictionary *)param
               withMethodType:(NSString *)aChannelName
                       result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    AgoraChatError *error =
        [AgoraChatClient.sharedClient.chatManager markAllConversationsAsRead];

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

- (void)getMessageCount:(NSDictionary *)param
                       withMethodType:(NSString *)aChannelName
                               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        getMessageCountWithCompletion:^(NSInteger count,
                                        AgoraChatError *_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;
    NSArray *conList = [AgoraChatClient.sharedClient.chatManager getAllConversations];
    int unreadCount = 0;
    AgoraChatError *error = nil;
    for (AgoraChatConversation *con in conList) {
        unreadCount += con.unreadMessagesCount;
    }

    [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;
    AgoraChatMessage *msg = [AgoraChatMessage fromJsonObject:param[@"message"]];
    AgoraChatMessage *dbMsg = [AgoraChatClient.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];

    [AgoraChatClient.sharedClient.chatManager
        updateMessage:dbMsg
           completion:^(AgoraChatMessage *aMessage, AgoraChatError *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:[AgoraChatMessage fromJsonObject:dict]];
    }
    [[AgoraChatClient sharedClient].chatManager importMessages:messages
                                             completion:^(AgoraChatError *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 AgoraChatMessage *msg =
        [AgoraChatMessage fromJsonObject:param[@"message"]];

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

    [AgoraChatClient.sharedClient.chatManager downloadMessageAttachment:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(AgoraChatMessage *message, AgoraChatError *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 AgoraChatMessage *msg =
        [AgoraChatMessage fromJsonObject:param[@"message"]];

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

    [AgoraChatClient.sharedClient.chatManager downloadMessageThumbnail:msg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(AgoraChatMessage *message, AgoraChatError *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 AgoraChatMessage *msg =
        [AgoraChatMessage fromJsonObject:param[@"message"]];

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

    AgoraChatMessage *needDownMSg = [AgoraChatClient.sharedClient.chatManager
        getMessageWithMessageId:msg.messageId];
    [AgoraChatClient.sharedClient.chatManager downloadMessageAttachment:needDownMSg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(AgoraChatMessage *message, AgoraChatError *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 AgoraChatMessage *msg =
        [AgoraChatMessage fromJsonObject:param[@"message"]];

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

    AgoraChatMessage *needDownMSg = [AgoraChatClient.sharedClient.chatManager
        getMessageWithMessageId:msg.messageId];
    [AgoraChatClient.sharedClient.chatManager downloadMessageThumbnail:needDownMSg
        progress:^(int progress) {
          [weakSelf onReceive:aChannelName
                   withParams:@{
                       @"progress" : @(progress),
                       @"localTime" : @(msg.localTime),
                       @"msgId" : msg.messageId,
                       @"callbackType" : ExtSdkMethodKeyOnMessageProgressUpdate
                   }];
        }
        completion:^(AgoraChatMessage *message, AgoraChatError *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)loadAllConversations:(NSDictionary *)param
              withMethodType:(NSString *)aChannelName
                      result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSArray *conversations =
        [AgoraChatClient.sharedClient.chatManager getAllConversations];
    NSArray *sortedList = [conversations
        sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1,
                                                       id _Nonnull obj2) {
          if (((AgoraChatConversation *)obj1).latestMessage.timestamp >
              ((AgoraChatConversation *)obj2).latestMessage.timestamp) {
              return NSOrderedAscending;
          } else {
              return NSOrderedDescending;
          }
        }];
    NSMutableArray *conList = [NSMutableArray array];
    for (AgoraChatConversation *conversation in sortedList) {
        [conList addObject:[conversation toJsonObject]];
    }

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

- (void)getConversationsFromServer:(NSDictionary *)param
                    withMethodType:(NSString *)aChannelName
                            result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        getConversationsFromServer:^(NSArray *aCoversations, AgoraChatError *aError) {
          NSArray *sortedList = [aCoversations
              sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1,
                                                             id _Nonnull obj2) {
                if (((AgoraChatConversation *)obj1).latestMessage.timestamp >
                    ((AgoraChatConversation *)obj2).latestMessage.timestamp) {
                    return NSOrderedAscending;
                } else {
                    return NSOrderedDescending;
                }
              }];
          NSMutableArray *conList = [NSMutableArray array];
          for (AgoraChatConversation *conversation in sortedList) {
              [conList addObject:[conversation toJsonObject]];
          }

          [weakSelf 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];
    [AgoraChatClient.sharedClient.chatManager
        deleteConversation:conversationId
          isDeleteMessages:isDeleteMsgs
                completion:^(NSString *aConversationId, AgoraChatError *aError) {
                  [weakSelf onResult:result
                      withMethodType:aChannelName
                           withError:aError
                          withParams:@(!aError)];
                }];
}

- (void)fetchHistoryMessages:(NSDictionary *)param
              withMethodType:(NSString *)aChannelName
                      result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *conversationId = param[@"convId"];
    AgoraChatConversationType type = (AgoraChatConversationType)[param[@"convType"] intValue];
    int pageSize = [param[@"pageSize"] intValue];
    NSString *startMsgId = param[@"startMsgId"];
    int direction = [param[@"direction"] intValue];
    [AgoraChatClient.sharedClient.chatManager
        asyncFetchHistoryMessagesFromServer:conversationId
                           conversationType:type
                             startMessageId:startMsgId
                             fetchDirection:
                                 (direction == 0
                                      ? AgoraChatMessageFetchHistoryDirectionUp
                                      : AgoraChatMessageFetchHistoryDirectionDown)
                                   pageSize:pageSize
                                 completion:^(AgoraChatCursorResult<AgoraChatMessage *>
                                                  *_Nullable aResult,
                                              AgoraChatError *_Nullable aError) {
                                   [weakSelf onResult:result
                                       withMethodType:aChannelName
                                            withError:aError
                                           withParams:[aResult toJsonObject]];
                                 }];
}

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

    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        asyncFetchGroupMessageAcksFromServer:msgId
                                     groupId:groupId
                             startGroupAckId:ackId
                                    pageSize:pageSize
                                  completion:^(AgoraChatCursorResult *aResult,
                                               AgoraChatError *aError,
                                               int totalCount) {
                                    [weakSelf onResult:result
                                        withMethodType:aChannelName
                                             withError:aError
                                            withParams:[aResult toJsonObject]];
                                  }];
}

- (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"];
    AgoraChatMessageSearchDirection direction =
        [self searchDirectionFromString:param[@"direction"]];
    AgoraChatMessageSearchScope scope =
        (AgoraChatMessageSearchScope)[param[@"searchScope"] integerValue];
    [AgoraChatClient.sharedClient.chatManager
        loadMessagesWithKeyword:keywords
                      timestamp:timeStamp
                          count:maxCount
                       fromUser:from
                searchDirection:direction
                          scope:scope
                     completion:^(NSArray<AgoraChatMessage *> *aMessages,
                                  AgoraChatError *aError) {
                       NSMutableArray *msgList = [NSMutableArray array];
                       for (AgoraChatMessage *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"];
    AgoraChatConversationType type = AgoraChatConversationTypeChat;
    BOOL isDeleteRemoteMessage = [param[@"isDeleteRemoteMessage"] boolValue];
    int intType = [param[@"conversationType"] intValue];
    if (intType == 0) {
        type = AgoraChatConversationTypeChat;
    } else if (intType == 1) {
        type = AgoraChatConversationTypeGroupChat;
    } else {
        type = AgoraChatConversationTypeChatRoom;
    }

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

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

    AgoraChatMessage *dbMsg = [AgoraChatClient.sharedClient.chatManager
        getMessageWithMessageId:msg.messageId];

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

    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        translateMessage:dbMsg
         targetLanguages:languages
              completion:^(AgoraChatMessage *message, AgoraChatError *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;
    [AgoraChatClient.sharedClient.chatManager
        fetchSupportedLanguages:^(
            NSArray<AgoraChatTranslateLanguage *> *_Nullable languages,
            AgoraChatError *_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;
    [AgoraChatClient.sharedClient.chatManager addReaction:reaction
                                         toMessage:msgId
                                        completion:^(AgoraChatError *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;
    [AgoraChatClient.sharedClient.chatManager removeReaction:reaction
                                          fromMessage:msgId
                                           completion:^(AgoraChatError *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"];
    AgoraChatType type =
        [AgoraChatMessage chatTypeFromInt:[param[@"chatType"] intValue]];
    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        getReactionList:msgIds
                groupId:groupId
               chatType:type
             completion:^(NSDictionary<NSString *, NSArray *> *dic,
                          AgoraChatError *error) {
               NSMutableDictionary *dictionary =
                   [NSMutableDictionary dictionary];
               for (NSString *key in dic.allKeys) {
                   NSArray *ary = dic[key];
                   NSMutableArray *list = [NSMutableArray array];
                   for (AgoraChatMessageReaction *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;
    [AgoraChatClient.sharedClient.chatManager
        getReactionDetail:msgId
                 reaction:reaction
                   cursor:cursor
                 pageSize:pageSize
               completion:^(AgoraChatMessageReaction *reaction,
                            NSString *_Nullable cursor, AgoraChatError *error) {
                 AgoraChatCursorResult *cursorResult = nil;
                 if (error == nil) {
                     cursorResult =
                         [AgoraChatCursorResult cursorResultWithList:@[ reaction ]
                                                    andCursor:cursor];
                 }

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

- (void)reportMessage:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {
    NSString *msgId = param[@"msgId"];
    NSString *tag = param[@"tag"];
    NSString *reason = param[@"reason"];
    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        reportMessageWithId:msgId
                        tag:tag
                     reason:reason
                 completion:^(AgoraChatError *error) {
                   [weakSelf onResult:result
                       withMethodType:aChannelName
                            withError:error
                           withParams:nil];
                 }];
}

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

- (void)fetchConversationsFromServerWithPage:(NSDictionary *)param
                              withMethodType:(NSString *)aChannelName
                                      result:(nonnull id<ExtSdkCallbackObjc>)
                                                 result {
    int pageSize = [param[@"pageSize"] intValue];
    int pageNum = [param[@"pageNum"] intValue];
    __weak typeof(self) weakSelf = self;
    [AgoraChatClient.sharedClient.chatManager
        getConversationsFromServerByPage:pageNum
                                pageSize:pageSize
                              completion:^(NSArray<AgoraChatConversation *>
                                               *_Nullable aConversations,
                                           AgoraChatError *_Nullable aError) {
                                NSArray *sortedList = [aConversations
                                    sortedArrayUsingComparator:
                                        ^NSComparisonResult(id _Nonnull obj1,
                                                            id _Nonnull obj2) {
                                          if (((AgoraChatConversation *)obj1)
                                                  .latestMessage.timestamp >
                                              ((AgoraChatConversation *)obj2)
                                                  .latestMessage.timestamp) {
                                              return NSOrderedAscending;
                                          } else {
                                              return NSOrderedDescending;
                                          }
                                        }];
                                NSMutableArray *conList =
                                    [NSMutableArray array];
                                for (AgoraChatConversation
                                         *conversation in sortedList) {
                                    [conList
                                        addObject:[conversation toJsonObject]];
                                }

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

- (void)removeMessagesFromServerWithMsgIds:(NSDictionary *)param
                            withMethodType:(NSString *)aChannelName
                                    result:
                                        (nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *convId = param[@"convId"];
    AgoraChatConversationType type =
        [AgoraChatConversation typeFromInt:[param[@"convType"] intValue]];
    AgoraChatConversation *conversation = [self getConversation:param];
    NSArray *msgIds = param[@"msgIds"];
    [conversation
        removeMessagesFromServerMessageIds:msgIds
                                completion:^(AgoraChatError *_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"];
    AgoraChatConversationType type =
        [AgoraChatConversation typeFromInt:[param[@"convType"] intValue]];
    long timestamp = [param[@"timestamp"] longValue];
    AgoraChatConversation *conversation = [self getConversation:param];
    [conversation
        removeMessagesFromServerWithTimeStamp:timestamp
                                   completion:^(AgoraChatError *_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"];
    AgoraChatConversationType type =
        [AgoraChatConversation typeFromInt:[param[@"convType"] intValue]];
    NSString *cursor = param[@"cursor"];
    int pageSize = [param[@"pageSize"] intValue];
    AgoraChatFetchServerMessagesOption *option =
        [AgoraChatFetchServerMessagesOption fromJsonObject:param[@"options"]];

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

- (void)getConversationsFromServerWithCursor:(NSDictionary *)param
                              withMethodType:(NSString *)aChannelName
                                      result:(nonnull id<ExtSdkCallbackObjc>)
                                                 result {
    __weak typeof(self) weakSelf = self;
    NSString *cursor = param[@"cursor"];
    int pageSize = [param[@"pageSize"] intValue];
    [AgoraChatClient.sharedClient.chatManager
        getConversationsFromServerWithCursor:cursor
                                    pageSize:pageSize
                                  completion:^(AgoraChatCursorResult<AgoraChatConversation *>
                                                   *_Nullable ret,
                                               AgoraChatError *_Nullable error) {
                                    [weakSelf onResult:result
                                        withMethodType:aChannelName
                                             withError:error
                                            withParams:[ret toJsonObject]];
                                  }];
}

- (void)getPinnedConversationsFromServerWithCursor:(NSDictionary *)param
                                    withMethodType:(NSString *)aChannelName
                                            result:
                                                (nonnull id<ExtSdkCallbackObjc>)
                                                    result {
    __weak typeof(self) weakSelf = self;
    NSString *cursor = param[@"cursor"];
    int pageSize = [param[@"pageSize"] intValue];
    [AgoraChatClient.sharedClient.chatManager
        getPinnedConversationsFromServerWithCursor:cursor
                                          pageSize:pageSize
                                        completion:^(
                                            AgoraChatCursorResult<AgoraChatConversation *>
                                                *_Nullable ret,
                                            AgoraChatError *_Nullable error) {
                                          [weakSelf onResult:result
                                              withMethodType:aChannelName
                                                   withError:error
                                                  withParams:[ret
                                                                 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];
    [AgoraChatClient.sharedClient.chatManager
        pinConversation:convId
               isPinned:isPinned
        completionBlock:^(AgoraChatError *_Nullable error) {
          [weakSelf onResult:result
              withMethodType:aChannelName
                   withError:error
                  withParams:nil];
        }];
}

- (void)modifyMessage:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msgId"];
    AgoraChatMessageBody *body = [AgoraChatTextMessageBody fromJsonObject:param[@"body"]];
    [AgoraChatClient.sharedClient.chatManager
        modifyMessage:msgId
                 body:body
           completion:^(AgoraChatError *_Nullable error,
                        AgoraChatMessage *_Nullable message) {
             [weakSelf onResult:result
                 withMethodType:aChannelName
                      withError:error
                     withParams:error != nil ? nil : [message toJsonObject]];
           }];
}

- (void)downloadAndParseCombineMessage:(NSDictionary *)param
                        withMethodType:(NSString *)aChannelName
                                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    AgoraChatMessage *msg = [AgoraChatMessage fromJsonObject:param[@"message"]];
    [AgoraChatClient.sharedClient.chatManager
        downloadAndParseCombineMessage:msg
                            completion:^(
                                NSArray<AgoraChatMessage *> *_Nullable messages,
                                AgoraChatError *_Nullable error) {
                              NSMutableArray *msgJsonAry =
                                  [NSMutableArray array];
                              for (AgoraChatMessage *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"];
    AgoraChatMarkType mark = (AgoraChatMarkType)[param[@"mark"] integerValue];
    [AgoraChatClient.sharedClient.chatManager
        addConversationMark:conversationIds
                       mark:mark
                 completion:^(AgoraChatError *_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"];
    AgoraChatMarkType mark = (AgoraChatMarkType)[param[@"mark"] integerValue];
    [AgoraChatClient.sharedClient.chatManager
        removeConversationMark:conversationIds
                          mark:mark
                    completion:^(AgoraChatError *_Nullable aError) {
                      [weakSelf onResult:result
                          withMethodType:aChannelName
                               withError:aError
                              withParams:nil];
                    }];
}

- (void)fetchConversationsByOptions:(NSDictionary *)param
                     withMethodType:(NSString *)aChannelName
                             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *cursor = [AgoraChatConversationFilter getCursor:param];
    BOOL isPinned = [AgoraChatConversationFilter getPinned:param];
    BOOL isMark = [AgoraChatConversationFilter hasMark:param];
    NSInteger pageSize = [AgoraChatConversationFilter pageSize:param];
    if (isPinned) {
        [AgoraChatClient.sharedClient.chatManager
            getPinnedConversationsFromServerWithCursor:cursor
                                              pageSize:pageSize
                                            completion:^(
                                                AgoraChatCursorResult<AgoraChatConversation *>
                                                    *_Nullable ret,
                                                AgoraChatError *_Nullable error) {
                                              [weakSelf onResult:result
                                                  withMethodType:aChannelName
                                                       withError:error
                                                      withParams:
                                                          [ret toJsonObject]];
                                            }];
        return;
    }

    if (isMark) {
        AgoraChatConversationFilter *filter =
            [AgoraChatConversationFilter fromJsonObject:param];
        [AgoraChatClient.sharedClient.chatManager
            getConversationsFromServerWithCursor:cursor
                                          filter:filter
                                      completion:^(
                                          AgoraChatCursorResult<AgoraChatConversation *>
                                              *_Nullable ret,
                                          AgoraChatError *_Nullable error) {
                                        [weakSelf onResult:result
                                            withMethodType:aChannelName
                                                 withError:error
                                                withParams:[ret toJsonObject]];
                                      }];
        return;
    }

    [AgoraChatClient.sharedClient.chatManager
        getConversationsFromServerWithCursor:cursor
                                    pageSize:pageSize
                                  completion:^(AgoraChatCursorResult<AgoraChatConversation *>
                                                   *_Nullable ret,
                                               AgoraChatError *_Nullable error) {
                                    [weakSelf onResult:result
                                        withMethodType:aChannelName
                                             withError:error
                                            withParams:[ret toJsonObject]];
                                  }];
}

- (void)deleteAllMessageAndConversation:(NSDictionary *)param
                         withMethodType:(NSString *)aChannelName
                                 result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    BOOL clearServerData = [param[@"clearServerData"] boolValue];
    [AgoraChatClient.sharedClient.chatManager
        deleteAllMessagesAndConversations:clearServerData
                               completion:^(AgoraChatError *_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"];
    [AgoraChatClient.sharedClient.chatManager
        pinMessage:msgId
        completion:^(AgoraChatMessage *_Nullable message,
                     AgoraChatError *_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"];
    [AgoraChatClient.sharedClient.chatManager
        unpinMessage:msgId
          completion:^(AgoraChatMessage *_Nullable message,
                       AgoraChatError *_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"];
    [AgoraChatClient.sharedClient.chatManager
        getPinnedMessagesFromServer:conversationId
                         completion:^(
                             NSArray<AgoraChatMessage *> *_Nullable messages,
                             AgoraChatError *_Nullable aError) {
                           NSMutableArray *msgList = [NSMutableArray array];
                           for (AgoraChatMessage *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 *types = [NSMutableArray array];
    for (NSString *type in typesJson) {
        [types addObject:[NSNumber numberWithInteger:[AgoraChatMessageBody
                                                         fromString:type]]];
    }
    long long timestamp = [param[@"timestamp"] longLongValue];
    int count = [param[@"count"] intValue];
    NSString *from = param[@"from"];
    AgoraChatMessageSearchDirection direction =
        [self searchDirectionFromString:param[@"direction"]];
    [AgoraChatClient.sharedClient.chatManager
        searchMessagesWithTypes:types
                      timestamp:timestamp
                          count:count
                       fromUser:from
                searchDirection:direction
                     completion:^(NSArray<AgoraChatMessage *> *_Nullable aMessages,
                                  AgoraChatError *_Nullable aError) {
                       NSMutableArray *msgs = [NSMutableArray array];
                       if (aMessages) {
                           for (AgoraChatMessage *msg in aMessages) {
                               [msgs addObject:[msg toJsonObject]];
                           }
                       }
                       [weakSelf onResult:result
                           withMethodType:aChannelName
                                withError:aError
                               withParams:msgs];
                     }];
}

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

#pragma mark - AgoraChatManagerDelegate

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

- (void)onConversationRead:(NSString *)from to:(NSString *)to {
    [self onReceive:ExtSdkMethodKeyOnConversationHasRead
         withParams:@{@"from" : from, @"to" : to}];
}

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

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

    [self onReceive:ExtSdkMethodKeyOnCmdMessagesReceived withParams:cmdMsgList];
}

- (void)messagesDidRead:(NSArray *)aMessages {
    NSMutableArray *list = [NSMutableArray array];
    for (AgoraChatMessage *msg in aMessages) {
        NSDictionary *json = [msg toJsonObject];
        [list addObject:json];
        [self onReceive:ExtSdkMethodKeyOnMessageReadAck withParams:json];
    }

    [self onReceive:ExtSdkMethodKeyOnMessagesRead withParams:list];
}

- (void)messagesDidDeliver:(NSArray *)aMessages {
    NSMutableArray *list = [NSMutableArray array];
    for (AgoraChatMessage *msg in aMessages) {
        NSDictionary *json = [msg toJsonObject];
        [list addObject:json];
        [self onReceive:ExtSdkMethodKeyOnMessageDeliveryAck
             withParams:@{@"message" : json}];
    }

    [self onReceive:ExtSdkMethodKeyOnMessagesDelivered withParams:list];
}

- (void)messagesInfoDidRecall:
    (NSArray<AgoraChatRecallMessageInfo *> *)aRecallMessagesInfo {
    NSMutableArray *list = [NSMutableArray array];
    for (AgoraChatRecallMessageInfo *info in aRecallMessagesInfo) {
        [list addObject:[info toJsonObject]];
    }

    [self onReceive:ExtSdkMethodKeyOnMessagesRecalledInfo withParams:list];
}

- (void)messageStatusDidChange:(AgoraChatMessage *)aMessage
                     withError:(AgoraChatError *)aError {
}

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

- (void)groupMessageDidRead:(AgoraChatMessage *)aMessage
                  groupAcks:(NSArray *)aGroupAcks {
    NSMutableArray *list = [NSMutableArray array];
    for (AgoraChatGroupMessageAck *ack in aGroupAcks) {
        NSDictionary *json = [ack toJsonObject];
        [list addObject:json];
    }

    [self onReceive:ExtSdkMethodKeyOnGroupMessageRead withParams:list];
}

- (AgoraChatMessageSearchDirection)searchDirectionFromString:(NSString *)aDirection {
    return [aDirection isEqualToString:@"up"] ? AgoraChatMessageSearchDirectionUp
                                              : AgoraChatMessageSearchDirectionDown;
}

- (void)groupMessageAckHasChanged {
    [self onReceive:ExtSdkMethodKeyChatOnReadAckForGroupMessageUpdated
         withParams:nil];
}

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

    [self onReceive:ExtSdkMethodKeyChatOnMessageReactionDidChange
         withParams:list];
}

- (void)onMessageContentChanged:(AgoraChatMessage *_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:(AgoraChatMessagePinOperation)pinOperation
                    pinInfo:(AgoraChatMessagePinInfo *_Nonnull)pinInfo {
    NSDictionary *dict = @{
        @"messageId" : messageId,
        @"conversationId" : conversationId,
        @"pinOperation" : @(pinOperation),
        @"pinInfo" : [pinInfo toJsonObject]
    };
    [self onReceive:ExtSdkMethodKeyonMessagePinChanged withParams:dict];
}

@end
