//
//  SLComposeTableViewController.m
//  PhotoShareExtension
//
//  Created by Russell on 8/5/15.
//
//

#import "ReceiverTableViewController.h"

typedef NS_ENUM(NSUInteger, NixTableViewSection) {
    kPlaylistHeader,
    kPlaylist,
    kFriendHeader,
    kFriend
};

@interface ReceiverTableViewController ()
@property (nonatomic, strong) NSArray *playlistValues;
@property (nonatomic, strong) NSArray *friendValues;
@property (nonatomic, strong) NSMutableArray *selectedPlaylists;
@property (nonatomic, strong) NSMutableArray *selectedFriends;
- (IBAction)send:(id)sender;
- (void)preparePlaylistValues;
- (void)prepareFriendValues;
- (void)reloadData;

- (NSString *)headerTitleWithPlaylistCounts:(NSUInteger)playlists andFriendCounts:(NSUInteger)friends;
- (void)updateHeaderTitleWithCounts;

- (void)loadAllData:(void (^)(NSError *))completionHandler;
- (void)loadPlaylistsWithCompletionHandler:(void (^)(NSError *))completionHandler;
- (void)loadFriendsWithCompletionHandler:(void (^)(NSError *))completionHandler;
@end

@implementation ReceiverTableViewController

#pragma mark - IB
- (IBAction)send:(id)sender {
    self.selectedPlaylists = [[NSMutableArray alloc]
                              initWithCapacity:self.containerViewController.playlistData.count];
    self.selectedFriends = [[NSMutableArray alloc]
                            initWithCapacity:self.containerViewController.friendData.count];
    
    NSArray *selectedIndexPaths = [self.tableView indexPathsForSelectedRows];
    [selectedIndexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
        @autoreleasepool {
            switch (indexPath.section) {
                case kPlaylist:
                {
                    NSString *playlistId = self.containerViewController.playlistData[indexPath.row][@"id"];
                    [self.selectedPlaylists addObject:playlistId];
                    break;
                }
                case kFriend:
                {
                    NSString *friendUsername = self.containerViewController.friendData[indexPath.row][@"username"];
                    [self.selectedFriends addObject:friendUsername];
                    break;
                }
                default:
                    break;
            }
        }
    }];

    self.containerViewController.playlistIds = [self.selectedPlaylists copy];
    self.containerViewController.friendUsernames = [self.selectedFriends copy];
    
    [self showActivityIndicator];
    self.navigationItem.rightBarButtonItem.enabled = NO;
    self.navigationItem.hidesBackButton = YES;
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    
    [self.containerViewController send];
}

#pragma mark - Navigation
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
    
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
    
    self.tableView.editing = YES;
    
    self.refreshControl = [[UIRefreshControl alloc] init];
    [self.refreshControl addTarget:self action:@selector(reloadData) forControlEvents:UIControlEventValueChanged];
    
    if (!self.containerViewController.playlistData || !self.containerViewController.friendData) {
        [self showActivityIndicator];
        [self loadAllData:^(NSError *error) {
            [self hideActivityIndicator];
            if (error) {
              UIAlertController *alertController =
              [UIAlertController alertControllerWithTitle:NSLocalizedString(@"signin_again_title", nil)
                                                  message:NSLocalizedString(@"signin_again_message", nil)
                                           preferredStyle:UIAlertControllerStyleAlert];
              [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"close", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                [self.containerViewController.extensionContext cancelRequestWithError:error];
              }]];
              [self presentViewController:alertController animated:YES completion:nil];
            } else {
              if (self.playlistValues.count == 0 && self.friendValues.count == 0) {
                NSError *err;
                UIAlertController *alertController =
                [UIAlertController alertControllerWithTitle:NSLocalizedString(@"no_receiver_title", nil)
                                                    message:NSLocalizedString(@"no_receiver_message", nil)
                                             preferredStyle:UIAlertControllerStyleAlert];
                [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"close", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                  [self.containerViewController.extensionContext cancelRequestWithError:err];
                }]];
                [self presentViewController:alertController animated:YES completion:nil];
              } else {
                [self.tableView reloadData];
              }
            }
        }];
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.navigationItem.rightBarButtonItem.enabled = NO;
    
    NSArray *selectedReceiverIndexPaths = self.containerViewController.selectedReceiverIndexPaths;
    
    [self.containerViewController verifyServiceAvailableWithCompletionHandler:^(BOOL success) {
        if ([selectedReceiverIndexPaths count]) {
            self.navigationItem.rightBarButtonItem.enabled = YES;
        }
    }];
    
    if (self.containerViewController.playlistData && self.containerViewController.friendData) {
        [self preparePlaylistValues];
        [self prepareFriendValues];
        
        [self.tableView reloadData];
        
        if ([selectedReceiverIndexPaths count]) {
            [selectedReceiverIndexPaths
             enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
                 [self.tableView selectRowAtIndexPath:indexPath
                                             animated:NO
                                       scrollPosition:UITableViewScrollPositionNone];
             }];
            [self updateHeaderTitleWithCounts];
        }
    }
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    self.friendValues = nil;
    self.playlistValues = nil;
    self.containerViewController.friendData = nil;
    self.containerViewController.playlistData = nil;
    self.containerViewController.selectedReceiverIndexPaths = nil; //[self.tableView indexPathsForSelectedRows];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Private
- (void)showActivityIndicator {
    UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
                                                  initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    self.navigationItem.titleView = activityIndicator;
    [activityIndicator startAnimating];
}

- (void)hideActivityIndicator {
    UIActivityIndicatorView *activityIndicator = (UIActivityIndicatorView *)self.navigationItem.titleView;
    if ([activityIndicator isKindOfClass:[UIActivityIndicatorView class]]) {
        [activityIndicator stopAnimating];
    }
    self.navigationItem.titleView = nil;
}

- (void)preparePlaylistValues {
    NSMutableArray *playlistValues = [NSMutableArray arrayWithCapacity:self.containerViewController.playlistData.count];
    for (NSDictionary *record in self.containerViewController.playlistData) {
        @autoreleasepool {
            NSString *name = record[@"name"];
            [playlistValues addObject:name];
        }
    }
    self.playlistValues = playlistValues;
}

- (void)prepareFriendValues {
    NSMutableArray *friendValues = [NSMutableArray arrayWithCapacity:self.containerViewController.friendData.count];
    for (NSDictionary *record in self.containerViewController.friendData) {
        @autoreleasepool {
            NSString *name = record[@"fullName"];
            [friendValues addObject:name];
        }
    }
    self.friendValues = friendValues;
}

- (void)reloadData {
    NSArray *playlistData = [self.containerViewController.playlistData copy];
    NSArray *friendData = [self.containerViewController.friendData copy];
    NSMutableArray *selectedPlaylistIds = [[NSMutableArray alloc] initWithCapacity:playlistData.count];
    NSMutableArray *selectedFriendUsernames = [[NSMutableArray alloc] initWithCapacity:friendData.count];
    
    [[self.tableView indexPathsForSelectedRows]
     enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
         switch (indexPath.section) {
             case kPlaylist:
                 [selectedPlaylistIds addObject:playlistData[indexPath.row][@"id"]];
                 break;
             case kFriend:
                 [selectedFriendUsernames addObject:friendData[indexPath.row][@"username"]];
                 break;
                 
             default:
                 break;
         }
     }];
    
    [self loadAllData:^(NSError *error) {
        [self.refreshControl endRefreshing];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSArray *freshPlaylistData = [self.containerViewController.playlistData copy];
            NSArray *freshFriendData = [self.containerViewController.friendData copy];
            
            [freshPlaylistData enumerateObjectsUsingBlock:^(NSDictionary *playlist, NSUInteger idx, BOOL *stop) {
                @autoreleasepool {
                    if ([selectedPlaylistIds containsObject:playlist[@"id"]]) {
                        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:kPlaylist];
                        [self.tableView selectRowAtIndexPath:indexPath
                                                    animated:NO
                                              scrollPosition:UITableViewScrollPositionNone];
                    }
                }
            }];
            
            [freshFriendData enumerateObjectsUsingBlock:^(NSDictionary *friend, NSUInteger idx, BOOL *stop) {
                @autoreleasepool {
                    if ([selectedFriendUsernames containsObject:friend[@"username"]]) {
                        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:kFriend];
                        [self.tableView selectRowAtIndexPath:indexPath
                                                    animated:NO
                                              scrollPosition:UITableViewScrollPositionNone];
                    }
                }
            }];
        });
    }];
}

- (NSString *)headerTitleWithPlaylistCounts:(NSUInteger)playlists andFriendCounts:(NSUInteger)friends {
    NSString *rawString;
    if (playlists == 0) {
        if (friends == 1) {
            rawString = NSLocalizedString(@"navigation_header_n_selected_friend", nil);
        } else {
            rawString = NSLocalizedString(@"navigation_header_n_selected_friends", nil);
        }
    }
    if (friends == 0) {
        if (playlists == 1) {
            rawString = NSLocalizedString(@"navigation_header_n_selected_playlist", nil);
        } else {
            rawString = NSLocalizedString(@"navigation_header_n_selected_playlists", nil);
        }
    }
    if (0 < playlists && 0 < friends) {
        rawString = NSLocalizedString(@"navigation_header_n_selected_receivers", nil);
    }
    if (playlists + friends == 0) {
        return NSLocalizedString(@"navigation_header_select_receivers", nil);
    }
    return [NSString stringWithFormat:rawString, playlists + friends];
}

- (void)updateHeaderTitleWithCounts {
    __block NSUInteger playlistCount = 0;
    __block NSUInteger friendCount = 0;
    [[self.tableView indexPathsForSelectedRows]
     enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
         switch (indexPath.section) {
             case kPlaylist:
                 playlistCount++;
                 break;
                 
             case kFriend:
                 friendCount++;
                 break;
         }
     }];
    NSString *title = [self headerTitleWithPlaylistCounts:playlistCount andFriendCounts:friendCount];
    self.navigationItem.title = title;
}

#pragma mark Network
- (void)loadAllData:(void (^)(NSError *))completionHandler {
    __block NSError *error = nil;
    
    dispatch_group_t dispatchGroup = dispatch_group_create();
    dispatch_group_enter(dispatchGroup);
    
    [self loadPlaylistsWithCompletionHandler:^(NSError *playlistsError) {
        if (playlistsError)
            error = playlistsError;
        dispatch_group_leave(dispatchGroup);
    }];
    
    dispatch_group_enter(dispatchGroup);
    [self loadFriendsWithCompletionHandler:^(NSError *friendsError) {
        if (friendsError)
            error = friendsError;
        dispatch_group_leave(dispatchGroup);
    }];
    
    dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
        completionHandler(error);
    });
}

- (void)loadPlaylistsWithCompletionHandler:(void (^)(NSError *))completionHandler {
    [self.containerViewController.api playlists:^(id data, NSURLResponse *response, NSError *error) {
        if (error || !data || [data isKindOfClass:[NSDictionary class]]) {
            completionHandler(error);
            return;
        }
        
        if ([data isKindOfClass:[NSArray class]]) {
            NSPredicate *predicateByTitle = [NSPredicate predicateWithFormat:@"SELF.type == %@", @"normal"];
            NSArray *playlists = [(NSArray*)data filteredArrayUsingPredicate:predicateByTitle];
            self.containerViewController.playlistData = playlists;
            [self preparePlaylistValues];
            [self.tableView reloadData];
        }
        
        completionHandler(nil);
    }];
}

- (void)loadFriendsWithCompletionHandler:(void (^)(NSError *))completionHandler {
    [self.containerViewController.api friends:^(NSDictionary *data, NSURLResponse *response, NSError *error) {
        if (error || data[@"error"]) {
            completionHandler(error);
            return;
        }
        NSString *predString = [NSString stringWithFormat:@"(status='%@')", @"success"];
        NSPredicate *pred = [NSPredicate predicateWithFormat:predString];
        NSArray *friendsArr = [data[@"friends"] filteredArrayUsingPredicate:pred];
        self.containerViewController.friendData = friendsArr;
        [self prepareFriendValues];
        [self.tableView reloadData];
        completionHandler(nil);
    }];
}

#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.
    return 4;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    switch (section) {
        case kPlaylistHeader:
            return self.playlistValues.count ? NSLocalizedString(@"table_header_playlist", nil) : nil;
        case kFriendHeader:
            return self.friendValues.count ? NSLocalizedString(@"table_header_friend", nil) : nil;
        default:
            return nil;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    switch (section) {
        case kPlaylist:
            return self.playlistValues.count;
        case kFriend:
            return self.friendValues.count;
        case kPlaylistHeader:
            return self.playlistValues.count ? 1 : 0;
        case kFriendHeader:
            return self.friendValues.count ? 1 : 0;
        default:
            return 0;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellId = @"SLComposeTableViewControllerCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
    }
    
    if ([[tableView indexPathsForSelectedRows] containsObject:indexPath]) {
        [tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    }
    
    switch (indexPath.section) {
        case kPlaylist:
            cell.textLabel.text = self.playlistValues[indexPath.row];
            break;
        case kFriend:
            cell.textLabel.text = self.friendValues[indexPath.row];
            break;
        case kPlaylistHeader:
            cell.textLabel.text = NSLocalizedString(@"table_select_all_playlists", nil);
            break;
        case kFriendHeader:
            cell.textLabel.text = NSLocalizedString(@"table_select_all_friends", nil);
            break;
        default:
            break;
    }
    return cell;
}

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/

/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    switch (indexPath.section) {
        case kPlaylistHeader:
        {
            for (NSUInteger i = 0; i < [tableView numberOfRowsInSection:kPlaylist]; i++) {
                NSIndexPath *playlistIndexPath = [NSIndexPath indexPathForRow:i inSection:kPlaylist];
                [tableView selectRowAtIndexPath:playlistIndexPath
                                       animated:NO
                                 scrollPosition:UITableViewScrollPositionNone];
            }
            break;
        }
            
        case kFriendHeader:
        {
            for (NSUInteger i = 0; i < [tableView numberOfRowsInSection:kFriend]; i++) {
                NSIndexPath *friendIndexPath = [NSIndexPath indexPathForRow:i inSection:kFriend];
                [tableView selectRowAtIndexPath:friendIndexPath
                                       animated:NO
                                 scrollPosition:UITableViewScrollPositionNone];
            }
            break;
        }
            
        default:
            break;
    }
    
    self.navigationItem.rightBarButtonItem.enabled = YES;
    [self updateHeaderTitleWithCounts];
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
    switch (indexPath.section) {
        case kPlaylistHeader:
        {
            for (NSUInteger i = 0; i < [tableView numberOfRowsInSection:kPlaylist]; i++) {
                NSIndexPath *playlistIndexPath = [NSIndexPath indexPathForRow:i inSection:kPlaylist];
                [tableView deselectRowAtIndexPath:playlistIndexPath
                                         animated:NO];
            }
            break;
        }
            
        case kFriendHeader:
        {
            for (NSUInteger i = 0; i < [tableView numberOfRowsInSection:kFriend]; i++) {
                NSIndexPath *friendIndexPath = [NSIndexPath indexPathForRow:i inSection:kFriend];
                [tableView deselectRowAtIndexPath:friendIndexPath
                                         animated:NO];
            }
            break;
        }
            
        case kPlaylist:
        {
            NSIndexPath *headerIndexPath = [NSIndexPath indexPathForRow:0 inSection:kPlaylistHeader];
            [tableView deselectRowAtIndexPath:headerIndexPath
                                     animated:NO];
            break;
        }
            
        case kFriend:
        {
            NSIndexPath *headerIndexPath = [NSIndexPath indexPathForRow:0 inSection:kFriendHeader];
            [tableView deselectRowAtIndexPath:headerIndexPath
                                     animated:NO];
            break;
        }
            
        default:
            break;
    }
    
    if (![tableView indexPathsForSelectedRows]) {
        self.navigationItem.rightBarButtonItem.enabled = NO;
    }
    [self updateHeaderTitleWithCounts];
}

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
