//
//  MBIMMessagesListOperation.m
//  kordophoned
//
//  Created by James Magahern on 11/13/18.
//  Copyright © 2018 James Magahern. All rights reserved.
//

#import "MBIMMessagesListOperation.h"
#import "MBIMHTTPUtilities.h"
#import "IMMessageItem+Encoded.h"
#import "MBIMErrorResponse.h"

#import "IMCore_ClassDump.h"

#define kDefaultMessagesLimit 75

@interface IMChat (MBIMSafeMessagesLoading)
- (void)load:(NSUInteger)number messagesBeforeGUID:(NSString *)beforeMessageGUID;
- (void)load:(NSUInteger)number messagesAfterGUID:(NSString *)afterMessageGUID;
@end

@implementation MBIMMessagesListOperation

+ (void)load { [super load]; }

+ (NSString *)endpointName
{
    return @"messages";
}

- (void)main
{
    __block NSObject<HTTPResponse> *response = nil;
    do {
        // Required parameters
        NSString *guid = [self valueForQueryItemWithName:@"guid"];
        
        // Optional
        NSString *limitValue = [self valueForQueryItemWithName:@"limit"];
        
        NSDate *beforeDate = nil;
        NSString *beforeDateValue = [self valueForQueryItemWithName:@"beforeDate"];
        if (beforeDateValue) {
            beforeDate = [beforeDateValue ISO8601Date];
            if (!beforeDate) {
                response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"Unable to decode ISO8601 beforeDate value"];
                break;
            }
        }
        
        NSString *beforeMessageGUID = [self valueForQueryItemWithName:@"beforeMessageGUID"];
        NSString *afterMessageGUID = [self valueForQueryItemWithName:@"afterMessageGUID"];
        
        if (beforeMessageGUID && afterMessageGUID) {
            response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"Cannot provide both beforeMessageGUID and afterMessageGUID params."];
            break;
        }
        
        if (!guid) {
            response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"No GUID provided."];
            break;
        }
        
        __block NSMutableArray *messages = [NSMutableArray array];
        dispatch_sync([[self class] sharedIMAccessQueue], ^{
            IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:guid];
            if (!chat) {
                MBIMLogInfo(@"Chat with guid: %@ not found", guid);
                response = [[HTTPErrorResponse alloc] initWithErrorCode:500];
            } else {
                // Load messages
                // (Must be done on main queue for some reason)
                dispatch_sync(dispatch_get_main_queue(), ^{
                    NSUInteger limit = kDefaultMessagesLimit;
                    if (limitValue) {
                        limit = [limitValue integerValue];
                    }
                    
                    if (beforeMessageGUID) {
                        [chat load:limit messagesBeforeGUID:beforeMessageGUID];
                    } else if (afterMessageGUID) {
                        [chat load:limit messagesAfterGUID:afterMessageGUID];
                    } else {
                        [chat loadMessagesBeforeDate:beforeDate limit:limit loadImmediately:YES];
                    }
                    
                    IMMessage *beforeMessage = beforeMessageGUID ? [chat messageForGUID:beforeMessageGUID] : nil;
                    IMMessage *afterMessage  = afterMessageGUID ? [chat messageForGUID:afterMessageGUID] : nil;
                    
                    [[chat chatItems] enumerateMessagesWithOptions:0 usingBlock:^(IMMessage *message, BOOL *stop) {
                        BOOL includeMessage = YES;
                        NSDate *messageDate = [message time];
                        if (beforeMessage && [[beforeMessage time] compare:messageDate] != NSOrderedDescending) {
                            includeMessage = NO;
                        }
                        
                        if (afterMessage && [[afterMessage time] compare:messageDate] != NSOrderedAscending) {
                            includeMessage = NO;
                        }
                        
                        if (includeMessage) {
                            NSDictionary *messageDict = [message mbim_dictionaryRepresentation];
                            [messages addObject:messageDict];
                        }
                    }];
                });
            }
        });
        
        response = [MBIMJSONDataResponse responseWithJSONObject:messages];
    } while (0);
    
    self.serverCompletionBlock(response);
}

@end

@implementation IMChat (MBIMSafeMessagesLoading)

- (id)_safe_loadMessagesBeforeAndAfterGUID:(NSString *)messagesGUID numberOfMessagesToLoadBeforeGUID:(NSUInteger)limitBefore numberOfMessagesToLoadAfterGUID:(NSUInteger)limitAfter loadImmediately:(BOOL)loadImmediately
{
    if ([self respondsToSelector:@selector(loadMessagesBeforeAndAfterGUID:
                                           numberOfMessagesToLoadBeforeGUID:
                                           numberOfMessagesToLoadAfterGUID:
                                           loadImmediately:threadIdentifier:)]) {
        return [self loadMessagesBeforeAndAfterGUID:messagesGUID
                   numberOfMessagesToLoadBeforeGUID:limitBefore
                    numberOfMessagesToLoadAfterGUID:limitAfter
                                    loadImmediately:YES threadIdentifier:nil];
    } else {
        return [self loadMessagesBeforeAndAfterGUID:messagesGUID
                   numberOfMessagesToLoadBeforeGUID:limitBefore
                    numberOfMessagesToLoadAfterGUID:limitAfter
                                    loadImmediately:YES];
    }
}

- (void)load:(NSUInteger)number messagesBeforeGUID:(NSString *)beforeMessageGUID
{
    [self _safe_loadMessagesBeforeAndAfterGUID:beforeMessageGUID numberOfMessagesToLoadBeforeGUID:number numberOfMessagesToLoadAfterGUID:0 loadImmediately:YES];
}

- (void)load:(NSUInteger)number messagesAfterGUID:(NSString *)afterMessageGUID
{
    [self _safe_loadMessagesBeforeAndAfterGUID:afterMessageGUID numberOfMessagesToLoadBeforeGUID:0 numberOfMessagesToLoadAfterGUID:number loadImmediately:YES];
}

@end
