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

#import "ExtSdkConversationWrapper.h"
#import "ExtSdkMethodTypeObjc.h"

#import "ExtSdkToJson.h"

@interface ExtSdkConversationWrapper ()

@end

@implementation ExtSdkConversationWrapper

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

#pragma mark - Private
- (void)getConversationWithParam:(NSDictionary *)param
                      completion:
                          (void (^)(AgoraChatConversation *conversation))aCompletion {
    AgoraChatConversation *conv;
    if (param[@"convId"]) {
        conv = [self getConversation:param];
    } else if (param[@"msg"]) {
        AgoraChatMessage *msg = [AgoraChatMessage fromJsonObject:param[@"msg"]];
        conv = [self getConversationFromMessage:msg];
    }

    if (aCompletion) {
        aCompletion(conv);
    }
}

#pragma mark - Actions
- (void)getUnreadMsgCount:(nullable NSDictionary *)param
           withMethodType:(NSString *)aChannelName
                   result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        [weakSelf onResult:result
                            withMethodType:ExtSdkMethodKeyGetUnreadMsgCount
                                 withError:nil
                                withParams:@(conversation.unreadMessagesCount)];
                      }];
}

- (void)getMsgCount:(nullable NSDictionary *)param
     withMethodType:(NSString *)aChannelName
             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          [weakSelf onResult:result
                              withMethodType:aChannelName
                                   withError:nil
                                  withParams:@(conversation.messagesCount)];
                        }];
}

- (void)getLatestMsg:(NSDictionary *)param
      withMethodType:(NSString *)aChannelName
              result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          AgoraChatMessage *msg = conversation.latestMessage;
                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeyGetLatestMsg
                                   withError:nil
                                  withParams:[msg toJsonObject]];
                        }];
}

- (void)getLatestMsgFromOthers:(NSDictionary *)param
                withMethodType:(NSString *)aChannelName
                        result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        AgoraChatMessage *msg = conversation.lastReceivedMessage;
                        [weakSelf onResult:result
                            withMethodType:ExtSdkMethodKeyGetLatestMsgFromOthers
                                 withError:nil
                                withParams:[msg toJsonObject]];
                      }];
}

- (void)markMsgAsRead:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSString *msgId = param[@"msg_id"];
                          AgoraChatError *error = nil;
                          [conversation markMessageAsReadWithId:msgId
                                                          error:&error];

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

- (void)syncConversationExt:(NSDictionary *)param
             withMethodType:(NSString *)aChannelName
                     result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSDictionary *ext = param[@"ext"];
                          conversation.ext = ext;
                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeySyncConversationExt
                                   withError:nil
                                  withParams:nil];
                        }];
}

- (void)markAllMsgsAsRead:(NSDictionary *)param
           withMethodType:(NSString *)aChannelName
                   result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          AgoraChatError *error = nil;
                          [conversation markAllMessagesAsRead:&error];
                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeyMarkAllMsgsAsRead
                                   withError:error
                                  withParams:nil];
                        }];
}

- (void)insertMsg:(NSDictionary *)param
    withMethodType:(NSString *)aChannelName
            result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSDictionary *msgDict = param[@"msg"];
                          AgoraChatMessage *msg =
                              [AgoraChatMessage fromJsonObject:msgDict];

                          AgoraChatError *error = nil;
                          [conversation insertMessage:msg error:&error];
                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeyInsertMsg
                                   withError:error
                                  withParams:nil];
                        }];
}

- (void)appendMsg:(NSDictionary *)param
    withMethodType:(NSString *)aChannelName
            result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSDictionary *msgDict = param[@"msg"];
                          AgoraChatMessage *msg =
                              [AgoraChatMessage fromJsonObject:msgDict];

                          AgoraChatError *error = nil;
                          [conversation appendMessage:msg error:&error];
                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeyAppendMsg
                                   withError:error
                                  withParams:nil];
                        }];
}

- (void)updateConversationMsg:(NSDictionary *)param
               withMethodType:(NSString *)aChannelName
                       result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        NSDictionary *msgDict = param[@"msg"];
                        AgoraChatMessage *msg =
                            [AgoraChatMessage fromJsonObject:msgDict];
                        AgoraChatMessage *dbMsg =
                            [AgoraChatClient.sharedClient.chatManager
                                getMessageWithMessageId:msg.messageId];
                        if ([weakSelf checkMessageParams:result
                                          withMethodType:aChannelName
                                             withMessage:msg]) {
                            return;
                        }
                        if ([weakSelf checkMessageParams:result
                                          withMethodType:aChannelName
                                             withMessage:dbMsg]) {
                            return;
                        }
                        [self mergeMessage:msg withDBMessage:dbMsg];

                        AgoraChatError *error = nil;
                        [conversation updateMessageChange:dbMsg error:&error];
                        [weakSelf onResult:result
                            withMethodType:ExtSdkMethodKeyUpdateConversationMsg
                                 withError:error
                                withParams:nil];
                      }];
}

- (void)removeMsg:(NSDictionary *)param
    withMethodType:(NSString *)aChannelName
            result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSString *msgId = param[@"msg_id"];
                          AgoraChatError *error = nil;
                          [conversation deleteMessageWithId:msgId error:&error];

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

- (void)clearAllMsg:(NSDictionary *)param
     withMethodType:(NSString *)aChannelName
             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          AgoraChatError *error = nil;
                          [conversation deleteAllMessages:&error];
                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeyClearAllMsg
                                   withError:error
                                  withParams:nil];
                        }];
}

- (void)deleteMessagesWithTimestamp:(NSDictionary *)param
                     withMethodType:(NSString *)aChannelName
                             result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          long startTs = [param[@"startTs"] longLongValue];
                          long endTs = [param[@"endTs"] longLongValue];
                          AgoraChatError *error =
                              [conversation removeMessagesStart:startTs
                                                             to:endTs];
                          [weakSelf onResult:result
                              withMethodType:aChannelName
                                   withError:error
                                  withParams:nil];
                        }];
}

- (void)pinnedMessages:(NSDictionary *)param
        withMethodType:(NSString *)aChannelName
                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSArray *pinnedMessages = conversation.pinnedMessages;
                          NSMutableArray *msgJsonAry = [NSMutableArray array];
                          for (AgoraChatMessage *msg in pinnedMessages) {
                              [msgJsonAry addObject:[msg toJsonObject]];
                          }
                          [weakSelf onResult:result
                              withMethodType:aChannelName
                                   withError:nil
                                  withParams:msgJsonAry];
                        }];
}

- (void)searchMessages:(NSDictionary *)param
        withMethodType:(NSString *)aChannelName
                result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        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 =
                            [param[@"direction"] integerValue];
                        [conversation
                            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)getMessageCountWithTimestamp:(NSDictionary *)param
                      withMethodType:(NSString *)aChannelName
                              result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          NSInteger start = [param[@"start"] integerValue];
                          NSInteger end = [param[@"end"] integerValue];
                          NSInteger ret =
                              [conversation getMessageCountStart:start to:end];
                          [weakSelf onResult:result
                              withMethodType:aChannelName
                                   withError:nil
                                  withParams:@(ret)];
                        }];
}

#pragma mark - load messages
- (void)loadMsgWithId:(NSDictionary *)param
       withMethodType:(NSString *)aChannelName
               result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *msgId = param[@"msg_id"];
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          AgoraChatError *error = nil;
                          AgoraChatMessage *msg =
                              [conversation loadMessageWithId:msgId
                                                        error:&error];

                          [weakSelf onResult:result
                              withMethodType:ExtSdkMethodKeyLoadMsgWithId
                                   withError:error
                                  withParams:[msg toJsonObject]];
                        }];
}

- (void)loadMsgWithMsgType:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;

    AgoraChatMessageBodyType type = [AgoraChatMessageBody fromString:param[@"msg_type"]];
    long long timeStamp = [param[@"timeStamp"] longLongValue];
    int count = [param[@"count"] intValue];
    NSString *sender = param[@"sender"];
    AgoraChatMessageSearchDirection direction =
        [self searchDirectionFromString:param[@"direction"]];

    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        [conversation
                            loadMessagesWithType:type
                                       timestamp:timeStamp
                                           count:count
                                        fromUser:sender
                                 searchDirection:direction
                                      completion:^(NSArray *aMessages,
                                                   AgoraChatError *aError) {
                                        NSMutableArray *msgJsonAry =
                                            [NSMutableArray array];
                                        for (AgoraChatMessage *msg in aMessages) {
                                            [msgJsonAry
                                                addObject:[msg toJsonObject]];
                                        }
                                        [weakSelf onResult:result
                                            withMethodType:
                                                ExtSdkMethodKeyLoadMsgWithMsgType
                                                 withError:aError
                                                withParams:msgJsonAry];
                                      }];
                      }];
}

- (void)loadMsgWithStartId:(NSDictionary *)param
            withMethodType:(NSString *)aChannelName
                    result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    NSString *startId = param[@"startId"];
    int count = [param[@"count"] intValue];
    AgoraChatMessageSearchDirection direction =
        [self searchDirectionFromString:param[@"direction"]];

    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        [conversation
                            loadMessagesStartFromId:startId
                                              count:count
                                    searchDirection:direction
                                         completion:^(NSArray *aMessages,
                                                      AgoraChatError *aError) {
                                           NSMutableArray *jsonMsgs =
                                               [NSMutableArray array];
                                           for (AgoraChatMessage
                                                    *msg in aMessages) {
                                               [jsonMsgs
                                                   addObject:[msg
                                                                 toJsonObject]];
                                           }

                                           [weakSelf onResult:result
                                               withMethodType:
                                                   ExtSdkMethodKeyLoadMsgWithStartId
                                                    withError:aError
                                                   withParams:jsonMsgs];
                                         }];
                      }];
}

- (void)loadMsgWithKeywords:(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 count = [param[@"count"] intValue];
    NSString *sender = param[@"sender"];
    AgoraChatMessageSearchDirection direction =
        [self searchDirectionFromString:param[@"direction"]];
    AgoraChatMessageSearchScope scope =
        (AgoraChatMessageSearchScope)[param[@"searchScope"] intValue];
    [self
        getConversationWithParam:param
                      completion:^(AgoraChatConversation *conversation) {
                        [conversation
                            loadMessagesWithKeyword:keywords
                                          timestamp:timestamp
                                              count:count
                                           fromUser:sender
                                    searchDirection:direction
                                              scope:scope
                                         completion:^(NSArray *aMessages,
                                                      AgoraChatError *aError) {
                                           NSMutableArray *msgJsonAry =
                                               [NSMutableArray array];
                                           for (AgoraChatMessage
                                                    *msg in aMessages) {
                                               [msgJsonAry
                                                   addObject:[msg
                                                                 toJsonObject]];
                                           }
                                           [weakSelf onResult:result
                                               withMethodType:
                                                   ExtSdkMethodKeyLoadMsgWithKeywords
                                                    withError:aError
                                                   withParams:msgJsonAry];
                                         }];
                      }];
}

- (void)loadMsgWithTime:(NSDictionary *)param
         withMethodType:(NSString *)aChannelName
                 result:(nonnull id<ExtSdkCallbackObjc>)result {
    __weak typeof(self) weakSelf = self;
    long long startTime = [param[@"startTime"] longLongValue];
    long long entTime = [param[@"endTime"] longLongValue];
    int count = [param[@"count"] intValue];
    [self getConversationWithParam:param
                        completion:^(AgoraChatConversation *conversation) {
                          [conversation
                              loadMessagesFrom:startTime
                                            to:entTime
                                         count:count
                                    completion:^(NSArray *aMessages,
                                                 AgoraChatError *aError) {
                                      NSMutableArray *msgJsonAry =
                                          [NSMutableArray array];
                                      for (AgoraChatMessage *msg in aMessages) {
                                          [msgJsonAry
                                              addObject:[msg toJsonObject]];
                                      }
                                      [weakSelf onResult:result
                                          withMethodType:
                                              ExtSdkMethodKeyLoadMsgWithTime
                                               withError:aError
                                              withParams:msgJsonAry];
                                    }];
                        }];
}

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

@end
