// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#import "OCTConversationViewController.h"
#import "OCTSubmanagerObjects.h"
#import "OCTSubmanagerChats.h"
#import "OCTFriend.h"
#import "OCTChat.h"
#import "OCTMessageAbstract.h"
#import "OCTSubmanagerUser.h"
#import "OCTSubmanagerCalls.h"
#import "OCTSubmanagerFiles.h"
#import "OCTMessageText.h"
#import "RLMCollectionChange+IndexSet.h"

static NSString *const kCellIdent = @"cellIdent";

@interface OCTConversationViewController () <NSTableViewDataSource,
                                             NSTableViewDelegate,
                                             NSTextFieldDelegate>

@property (weak) IBOutlet NSTableView *chatsViewController;
@property (weak, nonatomic) id<OCTManager> manager;

@property (strong, nonatomic) RLMResults<OCTChat *> *allChats;
@property (strong, nonatomic) RLMNotificationToken *allChatsNotificationToken;
@property (strong, nonatomic) RLMResults<OCTMessageAbstract *> *conversationMessages;
@property (strong, nonatomic) RLMNotificationToken *conversationMessagesNotificationToken;

@property (weak) IBOutlet NSTableView *chatsTableView;
@property (weak) IBOutlet NSTableView *conversationTableView;

@end

@implementation OCTConversationViewController

- (instancetype)initWithManager:(id<OCTManager>)manager
{
    self = [super init];

    if (! self) {
        return nil;
    }

    _manager = manager;

    _allChats = [self.manager.objects objectsForType:OCTFetchRequestTypeChat predicate:nil];
    _conversationMessages = nil;

    return self;
}

- (void)dealloc
{
    [self.allChatsNotificationToken invalidate];
    [self.conversationMessagesNotificationToken invalidate];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    __weak typeof(self)weakSelf = self;

    self.allChatsNotificationToken = [self.allChats addNotificationBlock:^(RLMResults *results, RLMCollectionChange *changes, NSError *error) {
        if (error) {
            NSLog(@"Failed to open Realm on background worker: %@", error);
            return;
        }

        NSTableView *tableView = weakSelf.chatsTableView;

        // Initial run of the query will pass nil for the change information
        if (! changes) {
            [tableView reloadData];
            return;
        }

        [tableView beginUpdates];
        [tableView removeRowsAtIndexes:[changes deletionsSet] withAnimation:NSTableViewAnimationSlideLeft];
        [tableView insertRowsAtIndexes:[changes insertionsSet] withAnimation:NSTableViewAnimationSlideRight];
        [tableView reloadDataForRowIndexes:[changes modificationsSet] columnIndexes:[NSIndexSet indexSetWithIndex:0]];
        [tableView endUpdates];
    }];
}

#pragma mark - Actions

- (IBAction)deleteChatButtonPressed:(NSButton *)sender
{
    NSInteger selectedRow = self.chatsTableView.selectedRow;

    if (selectedRow < 0) {
        return;
    }

    OCTChat *chat = self.allChats[selectedRow];

    [self.manager.chats removeAllMessagesInChat:chat removeChat:YES];
}

- (IBAction)callUserButtonPressed:(NSButton *)sender
{
    NSInteger selectedRow = self.chatsTableView.selectedRow;

    if (selectedRow < 0) {
        return;
    }

    OCTChat *chat = self.allChats[selectedRow];

    [self.manager.calls callToChat:chat enableAudio:YES enableVideo:YES error:nil];
}

- (IBAction)sendFileButtonPressed:(id)sender
{
    NSInteger selectedRow = self.chatsTableView.selectedRow;

    if (selectedRow < 0) {
        return;
    }

    OCTChat *chat = self.allChats[selectedRow];

    NSOpenPanel *panel = [NSOpenPanel openPanel];

    [panel runModal];

    NSString *path = [panel.URL path];

    [self.manager.files sendFileAtPath:path moveToUploads:NO toChat:chat failureBlock:nil];
}

#pragma mark - NSTextFieldDelegate

- (IBAction)chatTextFieldEntered:(NSTextField *)sender
{
    NSInteger selectedRow = self.chatsTableView.selectedRow;

    if (selectedRow < 0) {
        return;
    }

    OCTChat *chat = self.allChats[selectedRow];

    [self.manager.chats sendMessageToChat:chat
                                     text:sender.stringValue
                                     type:OCTToxMessageTypeNormal
                             successBlock:nil
                             failureBlock:nil];
    sender.stringValue = @"";
}

#pragma mark - NSTableViewDelegate

- (NSView *) tableView:(NSTableView *)tableView
    viewForTableColumn:(NSTableColumn *)tableColumn
                   row:(NSInteger)row
{
    NSTextField *field = [tableView
                          makeViewWithIdentifier:kCellIdent
                                           owner:self];

    if (! field) {
        field = [NSTextField new];
        field.identifier = kCellIdent;
    }

    field.selectable = YES;
    field.editable = NO;


    if (tableView == self.chatsTableView) {
        OCTChat *chat = self.allChats[row];
        OCTFriend *friend = [chat.friends firstObject];

        field.stringValue = (friend.isConnected) ? ([NSString stringWithFormat:@"%@ : Online", friend.nickname]) : friend.nickname;

    }
    else {
        OCTMessageAbstract *messageAbstract = self.conversationMessages[row];
        if (messageAbstract.messageText) {
            if ([messageAbstract isOutgoing]) {
                field.stringValue = [NSString stringWithFormat:@"%@: %@", self.manager.user.userName, messageAbstract.messageText.text];
            }
            else {
                OCTFriend *friend = (OCTFriend *)[self.manager.objects objectWithUniqueIdentifier:messageAbstract.senderUniqueIdentifier
                                                                                          forType:OCTFetchRequestTypeFriend];

                field.stringValue = [NSString stringWithFormat:@"%@: %@", friend.nickname, messageAbstract.messageText.text];
            }
        }
    }

    return field;
}

- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
    if (notification.object != self.chatsTableView) {
        return;
    }

    NSInteger selectedRow = self.chatsTableView.selectedRow;

    if (selectedRow < 0) {
        return;
    }

    OCTChat *chat = self.allChats[selectedRow];

    [self updateConversationControllerForChat:chat];

    [self.conversationTableView reloadData];
}

- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
{
    return 50.0;
}

#pragma mark - NSTableViewDataSource

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    if (tableView == self.chatsTableView) {
        return self.allChats.count;
    }
    else {
        return self.conversationMessages.count;
    }

    return 0;
}

#pragma mark - Private

- (void)updateConversationControllerForChat:(OCTChat *)chat
{
    [self.conversationMessagesNotificationToken invalidate];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"chatUniqueIdentifier == %@", chat.uniqueIdentifier];
    self.conversationMessages = [self.manager.objects objectsForType:OCTFetchRequestTypeMessageAbstract predicate:predicate];

    __weak typeof(self)weakSelf = self;

    self.conversationMessagesNotificationToken = [self.conversationMessages addNotificationBlock:^(RLMResults *results, RLMCollectionChange *changes, NSError *error) {
        if (error) {
            NSLog(@"Failed to open Realm on background worker: %@", error);
            return;
        }

        NSTableView *tableView = weakSelf.conversationTableView;

        // Initial run of the query will pass nil for the change information
        if (! changes) {
            [tableView reloadData];
            return;
        }

        [tableView beginUpdates];
        [tableView removeRowsAtIndexes:[changes deletionsSet] withAnimation:NSTableViewAnimationSlideLeft];
        [tableView insertRowsAtIndexes:[changes insertionsSet] withAnimation:NSTableViewAnimationSlideRight];
        [tableView reloadDataForRowIndexes:[changes modificationsSet] columnIndexes:[NSIndexSet indexSetWithIndex:0]];
        [tableView endUpdates];
    }];
}

@end
