#import "TGChannelMembersController.h"

#import "TGTelegraph.h"

#import "TGConversation.h"
#import "TGUser.h"
#import "TGDatabase.h"
#import "TGTelegramNetworking.h"

#import "TGButtonCollectionItem.h"
#import "TGGroupInfoUserCollectionItem.h"

#import "TGSelectContactController.h"

#import "TGChannelManagementSignals.h"

#import "TGProgressWindow.h"

#import "ActionStage.h"

#import "TGBotUserInfoController.h"
#import "TGTelegraphUserInfoController.h"

#import "TGGroupInfoShareLinkController.h"

#import "TGCommentCollectionItem.h"

#import "TGGroupInfoSelectContactController.h"

#import "TGNavigationController.h"
#import "TGNavigationBar.h"

#import "TGAlertView.h"

#import "TGChannelModeratorController.h"

#import "TGChannelMembersControllerEmptyView.h"

#import "TGVariantCollectionItem.h"
#import "TGHeaderCollectionItem.h"

#import "TGActionSheet.h"

@interface TGChannelMembersController () <ASWatcher, TGGroupInfoSelectContactControllerDelegate> {
    TGConversation *_conversation;
    TGChannelMembersMode _mode;
    id<SDisposable> _channelMembersDisposable;
    NSString *_privateLink;
    
    TGCollectionMenuSection *_adminSection;
    TGCollectionMenuSection *_usersSection;
    int _usersSectionPaddingTop;
    int _usersSectionPaddingBottom;
    
    TGCollectionMenuSection *_inviteControlSection;
    TGVariantCollectionItem *_inviteControlItem;
    TGCommentCollectionItem *_inviteControlComment;
    
    NSArray *_users;
    NSDictionary *_memberDatas;
    
    UIActivityIndicatorView *_activityIndicator;
    bool _editing;
    
    id<SDisposable> _cachedDataDisposable;
    
    TGChannelMembersControllerEmptyView *_emptyView;
}

@property (nonatomic, strong) ASHandle *actionHandle;

@end

@implementation TGChannelMembersController

- (instancetype)initWithConversation:(TGConversation *)conversation mode:(TGChannelMembersMode)mode {
    self = [super init];
    if (self != nil) {
        _conversation = conversation;
        _mode = mode;
        _actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
        
        switch (mode) {
            case TGChannelMembersModeMembers:
                self.title = TGLocalized(@"Channel.Members.Title");
                break;
            case TGChannelMembersModeBlacklist:
                self.title = TGLocalized(@"Channel.BlackList.Title");
                break;
            case TGChannelMembersModeAdmins:
                self.title = TGLocalized(@"Channel.Management.Title");
                break;
        }
        
        if (mode == TGChannelMembersModeAdmins && _conversation.isChannelGroup && _conversation.channelRole == TGChannelRoleCreator) {
            _inviteControlItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"ChannelMembers.WhoCanAddMembers") action:@selector(whoCanAddMembersPressed)];
            _inviteControlItem.deselectAutomatically = true;
            if (_conversation.everybodyCanAddMembers) {
                _inviteControlItem.variant = TGLocalized(@"ChannelMembers.WhoCanAddMembers.AllMembers");
            } else {
                _inviteControlItem.variant = TGLocalized(@"ChannelMembers.WhoCanAddMembers.Admins");
            }
            _inviteControlComment = [[TGCommentCollectionItem alloc] initWithText:@""];
            if (_conversation.everybodyCanAddMembers) {
                _inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAllHelp");
            } else {
                _inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAdminsHelp");
            }
            _inviteControlSection = [[TGCollectionMenuSection alloc] initWithItems:@[_inviteControlItem, _inviteControlComment]];
            [self.menuSections addSection:_inviteControlSection];
        }
        
        TGButtonCollectionItem *addMemberItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Members.AddMembers") action:@selector(addMembersPressed)];
        NSMutableArray *adminSectionItems = [[NSMutableArray alloc] init];
        [adminSectionItems addObject:addMemberItem];

        if (_conversation.username.length == 0) {
            TGButtonCollectionItem *linkItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Members.InviteLink") action:@selector(linkPressed)];
            [adminSectionItems addObject:linkItem];
        }
        
        TGCommentCollectionItem *addMemberHelpItem = [[TGCommentCollectionItem alloc] initWithFormattedText:TGLocalized(@"Channel.Members.AddMembersHelp")];
        [adminSectionItems addObject:addMemberHelpItem];
        
        TGHeaderCollectionItem *adminsTitleItem = [[TGHeaderCollectionItem alloc] initWithTitle:_conversation.isChannelGroup ? TGLocalized(@"ChannelMembers.GroupAdminsTitle") : TGLocalized(@"ChannelMembers.ChannelAdminsTitle")];
        TGButtonCollectionItem *addModeratorItem = [[TGButtonCollectionItem alloc] initWithTitle:TGLocalized(@"Channel.Management.AddModerator") action:@selector(addModeratorPressed)];
        addModeratorItem.leftInset = 65.0f;
        addModeratorItem.icon = [UIImage imageNamed:@"GroupInfoIconAddMember.png"];
        addModeratorItem.titleColor = TGAccentColor();
        addModeratorItem.deselectAutomatically = true;
        TGCommentCollectionItem *commentItem = [[TGCommentCollectionItem alloc] initWithFormattedText:_conversation.isChannelGroup ? TGLocalized(@"Group.Management.AddModeratorHelp") : TGLocalized(@"Channel.Management.AddModeratorHelp")];
        
        _adminSection = [[TGCollectionMenuSection alloc] initWithItems:adminSectionItems];
        
        switch (mode) {
            case TGChannelMembersModeMembers: {
                if (conversation.channelRole == TGChannelRoleCreator) {
                    [self.menuSections addSection:_adminSection];
                }
                break;
            }
            case TGChannelMembersModeAdmins: {
                break;
            }
            default:
                break;
        }
        
        NSMutableArray *usersSectionItems = [[NSMutableArray alloc] init];
        if (_mode == TGChannelMembersModeAdmins && conversation.channelRole == TGChannelRoleCreator) {
            [usersSectionItems addObject:adminsTitleItem];
            [usersSectionItems addObject:addModeratorItem];
            [usersSectionItems addObject:commentItem];
            _usersSectionPaddingTop = 1;
            _usersSectionPaddingBottom = 2;
        }
        _usersSection = [[TGCollectionMenuSection alloc] initWithItems:usersSectionItems];
        [self.menuSections addSection:_usersSection];
        
        TGCollectionMenuSection *topSection = self.menuSections.sections.firstObject;
        UIEdgeInsets topSectionInsets = topSection.insets;
        topSectionInsets.top = 32.0f;
        topSection.insets = topSectionInsets;
        
        SSignal *signal = nil;
        switch (_mode) {
            case TGChannelMembersModeMembers: {
                SSignal *cachedSignal = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
                    if (cachedData.generalMembers.count == 0) {
                        return [SSignal complete];
                    } else {
                        NSMutableArray *users = [[NSMutableArray alloc] init];
                        NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] init];
                        for (TGCachedConversationMember *member in cachedData.generalMembers) {
                            TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
                            if (user != nil) {
                                [users addObject:user];
                                memberDatas[@(member.uid)] = member;
                            }
                        }
                        return [SSignal single:@{@"users": users, @"memberDatas": memberDatas}];
                    }
                }];
                signal = [cachedSignal then:[[TGChannelManagementSignals channelMembers:conversation.conversationId accessHash:conversation.accessHash offset:0 count:128] onNext:^(NSDictionary *dict) {
                    
                    [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                        if (data == nil) {
                            data = [[TGCachedConversationData alloc] init];
                        }
                        return [data updateGeneralMembers:[dict[@"memberDatas"] allValues]];
                    }];
                }]];
                break;
            }
            case TGChannelMembersModeBlacklist: {
                SSignal *cachedSignal = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
                    if (cachedData.blacklistMembers.count == 0) {
                        return [SSignal single:@{@"users": @[], @"memberDatas": @{}}];
                    } else {
                        NSMutableArray *users = [[NSMutableArray alloc] init];
                        NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] init];
                        
                        for (TGCachedConversationMember *member in cachedData.blacklistMembers) {
                            TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
                            if (user != nil) {
                                [users addObject:user];
                                memberDatas[@(member.uid)] = member;
                            }
                        }
                        return [SSignal single:@{@"users": users, @"memberDatas": memberDatas}];
                    }
                }];
                signal = [cachedSignal then:[[[TGChannelManagementSignals channelBlacklistMembers:conversation.conversationId accessHash:conversation.accessHash offset:0 count:128] onNext:^(NSDictionary *dict) {
                    NSMutableArray *userIds = [[NSMutableArray alloc] init];
                    for (TGUser *user in dict[@"users"]) {
                        [userIds addObject:@(user.uid)];
                    }
                    
                    [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                        if (data == nil) {
                            data = [[TGCachedConversationData alloc] init];
                        }
                        return [data updateBlacklistMembers:[dict[@"memberDatas"] allValues]];
                    }];
                }] map:^id(NSDictionary *dict) {
                    NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
                    updatedDict[@"final"] = @(true);
                    return updatedDict;
                }]];
                break;
            }
            case TGChannelMembersModeAdmins: {
                SSignal *cachedSignal = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] take:1] mapToSignal:^SSignal *(TGCachedConversationData *cachedData) {
                    if (cachedData.managementMembers.count == 0) {
                        return [SSignal complete];
                    } else {
                        NSMutableArray *users = [[NSMutableArray alloc] init];
                        NSMutableDictionary *memberDatas = [[NSMutableDictionary alloc] init];
                        
                        for (TGCachedConversationMember *member in cachedData.managementMembers) {
                            TGUser *user = [TGDatabaseInstance() loadUser:member.uid];
                            if (user != nil) {
                                [users addObject:user];
                                memberDatas[@(member.uid)] = member;
                            }
                        }
                        return [SSignal single:@{@"users": users, @"memberDatas": memberDatas}];
                    }
                }];
                
                signal = [cachedSignal then:[[TGChannelManagementSignals channelAdmins:conversation.conversationId accessHash:conversation.accessHash offset:0 count:128] onNext:^(NSDictionary *dict) {
                    
                    [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                        if (data == nil) {
                            data = [[TGCachedConversationData alloc] init];
                        }
                        return [data updateManagementMembers:[dict[@"memberDatas"] allValues]];
                    }];
                }]];
                break;
            }
        }
        
        __weak TGChannelMembersController *weakSelf = self;
        _channelMembersDisposable = [[signal deliverOn:[SQueue mainQueue]] startWithNext:^(NSDictionary *dict) {
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                [self setUsers:dict[@"users"] memberDatas:dict[@"memberDatas"] isFinal:[dict[@"final"] boolValue]];
            }
        }];
        
        _cachedDataDisposable = [[[TGDatabaseInstance() channelCachedData:_conversation.conversationId] deliverOn:[SQueue mainQueue]] startWithNext:^(TGCachedConversationData *cachedData) {
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                strongSelf->_privateLink = cachedData.privateLink;
            }
        }];
    }
    return self;
}

- (void)dealloc {
    [_channelMembersDisposable dispose];
    [_actionHandle reset];
    [ActionStageInstance() removeWatcher:self];
}

- (void)updateEmptyState:(bool)empty {
    if (empty && _mode == TGChannelMembersModeBlacklist) {
        if (_emptyView == nil) {
            _emptyView = [[TGChannelMembersControllerEmptyView alloc] initWithText:TGLocalized(@"ChannelMembers.Blacklist.EmptyText")];
        }
        _emptyView.frame = self.view.bounds;
        _emptyView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        [self.view addSubview:_emptyView];
    } else {
        [_emptyView removeFromSuperview];
        _emptyView = nil;
    }
}

- (void)editPressed {
    _editing = true;
    [self enterEditingMode:true];
    
    [self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(donePressed)] animated:true];
    [self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@" " style:UIBarButtonItemStylePlain target:self action:@selector(noAction)] animated:true];
}

- (void)noAction {
}

- (void)donePressed {
    _editing = false;
    [self leaveEditingMode:true];
    
    [self setLeftBarButtonItem:nil animated:true];
    
    if (_users.count != 0) {
        [self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editPressed)] animated:true];
    }
}

- (void)setUsers:(NSArray *)users memberDatas:(NSDictionary *)memberDatas isFinal:(bool)isFinal {
    TGDispatchOnMainThread(^{
        _users = [users sortedArrayUsingComparator:^NSComparisonResult(TGUser *user1, TGUser *user2) {
            if (user1.uid == TGTelegraphInstance.clientUserId) {
                return NSOrderedAscending;
            } else if (user2.uid == TGTelegraphInstance.clientUserId) {
                return NSOrderedDescending;
            }
            
            TGCachedConversationMember *member1 = memberDatas[@(user1.uid)];
            TGCachedConversationMember *member2 = memberDatas[@(user2.uid)];
            
            switch (_mode) {
                case TGChannelMembersModeBlacklist: {
                    if (member1.timestamp > member2.timestamp) {
                        return NSOrderedAscending;
                    } else if (member1.timestamp < member2.timestamp) {
                        return NSOrderedDescending;
                    }
                    
                    return user1.uid < user2.uid;
                }
                case TGChannelMembersModeAdmins: {
                    return member1.role > member2.role ? NSOrderedAscending : NSOrderedDescending;
                }
                default: {
                    if (user1.botKind != user2.botKind) {
                        return user1.botKind < user2.botKind ? NSOrderedAscending : NSOrderedDescending;
                    }
                    
                    if (user1.kind != user2.kind) {
                        return user1.kind < user2.kind ? NSOrderedAscending : NSOrderedDescending;
                    }
                    
                    if (user1.presence.online != user2.presence.online)
                        return user1.presence.online ? NSOrderedAscending : NSOrderedDescending;
                    
                    if ((user1.presence.lastSeen < 0) != (user2.presence.lastSeen < 0))
                        return user1.presence.lastSeen >= 0 ? NSOrderedAscending : NSOrderedDescending;
                    
                    if (user1.presence.online) {
                        return member1.timestamp > member2.timestamp ? NSOrderedAscending : NSOrderedDescending;
                    }
                    
                    if (user1.presence.lastSeen < 0) {
                        return member1.timestamp > member2.timestamp ? NSOrderedAscending : NSOrderedDescending;
                    }
                    
                    return user1.presence.lastSeen > user2.presence.lastSeen ? NSOrderedAscending : NSOrderedDescending;
                }
            }
            
            return NSOrderedSame;
        }];
        _memberDatas = memberDatas;
        
        [self updateEditing];
        
        self.collectionView.hidden = false;
        [_activityIndicator removeFromSuperview];
        _activityIndicator = nil;
        
        if (isFinal || true) {
            [self updateEmptyState:_users.count == 0];
        }
        
        while (_usersSection.items.count > (NSUInteger)(_usersSectionPaddingTop + _usersSectionPaddingBottom)) {
            [_usersSection deleteItemAtIndex:_usersSectionPaddingTop];
        }
        
        bool canDeleteUsers = _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRolePublisher;
        switch (_mode) {
            case TGChannelMembersModeMembers: {
                break;
            }
            case TGChannelMembersModeAdmins: {
                canDeleteUsers = _conversation.channelRole == TGChannelRoleCreator;
                break;
            }
            case TGChannelMembersModeBlacklist: {
                break;
            }
        }
        
        for (TGUser *user in _users) {
            TGGroupInfoUserCollectionItem *userItem = [[TGGroupInfoUserCollectionItem alloc] init];
            
            userItem.interfaceHandle = _actionHandle;
            
            bool disabled = false;
            userItem.selectable = user.uid != TGTelegraphInstance.clientUserId && !disabled;
            
            bool canEditInPrinciple = user.uid != TGTelegraphInstance.clientUserId && canDeleteUsers;
            
            bool canEdit = userItem.selectable && canEditInPrinciple;
            [userItem setCanEdit:canEdit];
            
            [userItem setUser:user];
            [userItem setDisabled:disabled];
            
            TGCachedConversationMember *member = memberDatas[@(user.uid)];
            if (member != nil) {
                if (_mode == TGChannelMembersModeAdmins) {
                    switch (member.role) {
                        case TGChannelRoleCreator:
                            [userItem setCustomStatus:TGLocalized(@"Channel.Management.LabelCreator")];
                            break;
                        case TGChannelRoleModerator:
                            [userItem setCustomStatus:TGLocalized(@"Channel.Management.LabelModerator")];
                            break;
                        case TGChannelRolePublisher:
                            [userItem setCustomStatus:TGLocalized(@"Channel.Management.LabelEditor")];
                            break;
                        default:
                            break;
                    }
                }
            }
            NSString *optionTitle = nil;
            switch (_mode) {
                case TGChannelMembersModeMembers: {
                    optionTitle = TGLocalized(@"Channel.Members.Kick");
                    break;
                }
                case TGChannelMembersModeBlacklist: {
                    optionTitle = TGLocalized(@"Channel.Management.Remove");
                    break;
                }
                case TGChannelMembersModeAdmins: {
                    optionTitle = TGLocalized(@"Channel.Management.Remove");
                    break;
                }
            }
            userItem.optionTitle = optionTitle;
            [_usersSection insertItem:userItem atIndex:_usersSectionPaddingTop + _usersSection.items.count - _usersSectionPaddingTop - _usersSectionPaddingBottom];
        }
        
        [self.collectionView reloadData];
    });
}

- (void)updateEditing {
    bool canEdit = false;
    for (int i = _usersSectionPaddingTop; i < (int)_usersSection.items.count - _usersSectionPaddingBottom; i++) {
        TGGroupInfoUserCollectionItem *item = _usersSection.items[i];
        if (item.user.uid != TGTelegraphInstance.clientUserId) {
            canEdit = true;
        }
    }
    
    if (canEdit) {
        switch (_mode) {
            case TGChannelMembersModeAdmins:
                canEdit = _conversation.channelRole == TGChannelRoleCreator;
                break;
            case TGChannelMembersModeBlacklist:
                canEdit = _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRoleModerator;
            case TGChannelMembersModeMembers:
                canEdit = _conversation.channelRole == TGChannelRoleCreator || _conversation.channelRole == TGChannelRoleModerator || _conversation.channelRole == TGChannelRoleModerator;
        }
    }
    
    if (canEdit) {
        [self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editPressed)]];
    } else {
        [self setLeftBarButtonItem:nil animated:false];
        [self setRightBarButtonItem:nil animated:false];
        if (_editing) {
            [self leaveEditingMode:true];
        }
    }
}

- (void)loadView {
    [super loadView];
    
    if (_users == nil) {
        self.collectionView.hidden = true;
        
        [_activityIndicator removeFromSuperview];
        
        _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        _activityIndicator.frame = CGRectMake(CGFloor((self.view.bounds.size.width - _activityIndicator.frame.size.width) / 2.0f), CGFloor((self.view.bounds.size.height - _activityIndicator.frame.size.height) / 2.0f), _activityIndicator.frame.size.width, _activityIndicator.frame.size.height);
        _activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
        [self.view addSubview:_activityIndicator];
        [_activityIndicator startAnimating];
    }
}

- (void)addMembersPressed {
    TGSelectContactController *selectController = [[TGSelectContactController alloc] initWithCreateGroup:false createEncrypted:false createBroadcast:false createChannel:false inviteToChannel:true showLink:false];
    selectController.ignoreBots = true;
    selectController.channelConversation = _conversation;
    selectController.deselectAutomatically = true;
    NSMutableArray *existingUsers = [[NSMutableArray alloc] init];
    for (TGUser *user in _users) {
        [existingUsers addObject:@(user.uid)];
    }
    selectController.disabledUsers = existingUsers;
    __weak TGChannelMembersController *weakSelf = self;
    selectController.onChannelMembersInvited = ^(NSArray *users) {
        __strong TGChannelMembersController *strongSelf = weakSelf;
        if (strongSelf != nil) {
            NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
            NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
            for (TGUser *user in users) {
                if (updatedMemberDatas[@(user.uid)] != nil) {
                    continue;
                }
                
                updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleMember timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
                [updatedUsers addObject:user];
            }
            
            [strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas isFinal:true];
        }
    };
    TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[selectController]];
    [self presentViewController:navigationController animated:true completion:nil];
}

- (void)actionStageActionRequested:(NSString *)action options:(id)options {
    if ([action isEqualToString:@"deleteUser"])
    {
        int32_t uid = [options[@"uid"] int32Value];
        if (uid != 0)
            [self _commitDeleteParticipant:uid];
    }
    else if ([action isEqualToString:@"openUser"])
    {
        int32_t uid = [options[@"uid"] int32Value];
        if (uid != 0)
        {
            TGUser *user = [TGDatabaseInstance() loadUser:uid];
            
            switch (_mode) {
                case TGChannelMembersModeAdmins: {
                    /*TGChannelModeratorController *controller = [[TGChannelModeratorController alloc] initWithConversation:_conversation user:user member:_memberDatas[@(user.uid)]];
                    __weak TGChannelMembersController *weakSelf = self;
                    TGConversation *conversation = _conversation;
                    controller.done = ^(TGCachedConversationMember *member) {
                        __strong TGChannelMembersController *strongSelf = weakSelf;
                        if (strongSelf != nil) {
                            if (member == nil) {
                                SSignal *signal = [[TGChannelManagementSignals channelChangeRole:_conversation.conversationId accessHash:_conversation.accessHash user:user role:TGChannelRoleMember] onCompletion:^{
                                    [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                                        if (data == nil) {
                                            data = [[TGCachedConversationData alloc] init];
                                        }
                                        
                                        return [data removeManagementMember:user.uid];
                                    }];
                                }];
                                
                                TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
                                [progressWindow show:true];
                                
                                [[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
                                    TGDispatchOnMainThread(^{
                                        [progressWindow dismiss:true];
                                    });
                                }] startWithNext:nil completed:^{
                                    __strong TGChannelMembersController *strongSelf = weakSelf;
                                    if (strongSelf != nil) {
                                        NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
                                        NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
                                        NSUInteger index = 0;
                                        for (TGUser *user in updatedUsers) {
                                            if (user.uid == uid) {
                                                [updatedUsers removeObjectAtIndex:index];
                                                [updatedMemberDatas removeObjectForKey:@(user.uid)];
                                                [strongSelf->_usersSection deleteItemAtIndex:index];
                                                
                                                strongSelf->_users = updatedUsers;
                                                strongSelf->_memberDatas = updatedMemberDatas;
                                                
                                                [strongSelf updateEditing];
                                                
                                                [strongSelf.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:[strongSelf indexForSection:strongSelf->_usersSection]]]];
                                                [strongSelf updateItemPositions];
                                                
                                                break;
                                            }
                                            index++;
                                        }
                                        
                                        [strongSelf.navigationController popToViewController:strongSelf animated:true];
                                    }
                                }];
                            } else if (member.role != ((TGCachedConversationMember *)strongSelf->_memberDatas[@(user.uid)]).role) {
                                SSignal *signal = [[TGChannelManagementSignals channelChangeRole:_conversation.conversationId accessHash:_conversation.accessHash user:user role:member.role] onCompletion:^{
                                    [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                                        if (data == nil) {
                                            data = [[TGCachedConversationData alloc] init];
                                        }
                                        
                                        return [data addManagementMember:member];
                                    }];
                                }];
                                
                                TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
                                [progressWindow show:true];
                                
                                [[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
                                    TGDispatchOnMainThread(^{
                                        [progressWindow dismiss:true];
                                    });
                                }] startWithNext:nil completed:^{
                                    __strong TGChannelMembersController *strongSelf = weakSelf;
                                    if (strongSelf != nil) {
                                        NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
                                        NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
                                        updatedMemberDatas[@(uid)] = [[TGCachedConversationMember alloc] initWithUid:uid role:member.role timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
                                        
                                        [strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas];
                                        [strongSelf.navigationController popToViewController:strongSelf animated:true];
                                    }
                                }];
                            } else {
                                [strongSelf.navigationController popToViewController:strongSelf animated:true];
                            }
                        }
                    };
                    [self.navigationController pushViewController:controller animated:true];
                    
                    break;*/
                }
                default: {
                    if (user.kind == TGUserKindBot || user.kind == TGUserKindSmartBot) {
                        TGBotUserInfoController *userInfoController = [[TGBotUserInfoController alloc] initWithUid:uid sendCommand:nil];
                        [self.navigationController pushViewController:userInfoController animated:true];
                    }
                    else {
                        TGTelegraphUserInfoController *userInfoController = [[TGTelegraphUserInfoController alloc] initWithUid:uid];
                        [self.navigationController pushViewController:userInfoController animated:true];
                    }
                    
                    break;
                }
            }
        }
    }
}

- (void)_commitDeleteParticipant:(int32_t)userId {
    TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
    [progressWindow showWithDelay:0.5];
    
    TGUser *user = [TGDatabaseInstance() loadUser:userId];
    
    TGConversation *conversation = _conversation;
    
    SSignal *signal = nil;
    switch (_mode) {
        case TGChannelMembersModeMembers: {
            signal = [[TGChannelManagementSignals channelChangeMemberKicked:_conversation.conversationId accessHash:_conversation.accessHash user:user kicked:true] onCompletion:^{
                [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                    if (data == nil) {
                        data = [[TGCachedConversationData alloc] init];
                    }
                    
                    return [data blacklistMember:userId timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
                }];
            }];
            break;
        }
        case TGChannelMembersModeBlacklist: {
            signal = [[TGChannelManagementSignals channelChangeMemberKicked:_conversation.conversationId accessHash:_conversation.accessHash user:user kicked:false] onCompletion:^{
                [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                    if (data == nil) {
                        data = [[TGCachedConversationData alloc] init];
                    }
                    
                    return [data unblacklistMember:userId timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
                }];
            }];
            break;
        }
        case TGChannelMembersModeAdmins: {
            signal = [[TGChannelManagementSignals channelChangeRole:_conversation.conversationId accessHash:_conversation.accessHash user:user role:TGChannelRoleMember] onCompletion:^{
                [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                    if (data == nil) {
                        data = [[TGCachedConversationData alloc] init];
                    }
                    
                    return [data removeManagementMember:userId];
                }];
            }];
            break;
        }
    }
    
    __weak TGChannelMembersController *weakSelf = self;
    [[[signal deliverOn:[SQueue mainQueue]] onDispose:^{
        TGDispatchOnMainThread(^{
            [progressWindow dismiss:true];
        });
    }] startWithNext:nil completed:^{
        __strong TGChannelMembersController *strongSelf = weakSelf;
        if (strongSelf != nil) {
            NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
            NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
            NSUInteger index = 0;
            for (TGUser *user in updatedUsers) {
                if (user.uid == userId) {
                    [updatedUsers removeObjectAtIndex:index];
                    [updatedMemberDatas removeObjectForKey:@(user.uid)];
                    [strongSelf->_usersSection deleteItemAtIndex:strongSelf->_usersSectionPaddingTop + index];
                    
                    strongSelf->_users = updatedUsers;
                    strongSelf->_memberDatas = updatedMemberDatas;
                    
                    [strongSelf updateEditing];
                    
                    [strongSelf.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:strongSelf->_usersSectionPaddingTop + index inSection:[strongSelf indexForSection:strongSelf->_usersSection]]]];
                    [strongSelf updateItemPositions];
                    
                    break;
                }
                index++;
            }
        }
    }];
}

- (void)linkPressed {
    TGGroupInfoShareLinkController *controller = [[TGGroupInfoShareLinkController alloc] initWithPeerId:_conversation.conversationId accessHash:_conversation.accessHash currentLink:_privateLink];
    [self.navigationController pushViewController:controller animated:true];
}

- (void)addModeratorPressed {
    int contactsMode = TGContactsModeRegistered | TGContactsModeManualFirstSection;
    contactsMode |= TGContactsModeIgnorePrivateBots;
    TGGroupInfoSelectContactController *selectContactController = [[TGGroupInfoSelectContactController alloc] initWithContactsMode:contactsMode];
    selectContactController.deselectAutomatically = true;
    selectContactController.delegate = self;
    
    NSMutableArray *disabledUsers = [[NSMutableArray alloc] init];
    
    NSMutableArray *userIds = [[NSMutableArray alloc] init];
    for (TGUser *user in _users) {
        [userIds addObject:@(user.uid)];
    }
    
    [disabledUsers addObjectsFromArray:userIds];
    
    selectContactController.disabledUsers = disabledUsers;
    
    TGNavigationController *navigationController = [TGNavigationController navigationControllerWithControllers:@[selectContactController] navigationBarClass:[TGWhiteNavigationBar class]];
    if ([self inPopover]) {
        navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
        navigationController.presentationStyle = TGNavigationControllerPresentationStyleChildInPopover;
    }
    
    [self presentViewController:navigationController animated:true completion:nil];
}

- (SSignal *)modifyMemberRole:(TGUser *)user role:(TGChannelRole)role {
    __weak TGChannelMembersController *weakSelf = self;
    TGConversation *conversation = _conversation;
    
    return [[SSignal defer:^SSignal *{
        SSignal *changeSignal = [[TGChannelManagementSignals channelChangeRole:conversation.conversationId accessHash:conversation.accessHash user:user role:role] onCompletion:^{
            [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                if (data == nil) {
                    data = [[TGCachedConversationData alloc] init];
                }
                
                return [data addManagementMember:[[TGCachedConversationMember alloc] initWithUid:user.uid role:role timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]]];
            }];
        }];
        
        __block TGProgressWindow *progressWindow = nil;
        
        return [[[[[changeSignal deliverOn:[SQueue mainQueue]] onStart:^{
            progressWindow = [[TGProgressWindow alloc] init];
            [progressWindow show:true];
        }] onDispose:^{
            TGDispatchOnMainThread(^{
                [progressWindow dismiss:true];
            });
        }] onCompletion:^{
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
                NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
                if (updatedMemberDatas[@(user.uid)] == nil) {
                    [updatedUsers addObject:user];
                }
                
                updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:role timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
                
                [strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas isFinal:true];
                [strongSelf updateEditing];
            }
        }] onError:^(id error) {
            TGDispatchOnMainThread(^{
                NSString *errorType = [[TGTelegramNetworking instance] extractNetworkErrorType:error];
                NSString *errorText = TGLocalized(@"Profile.CreateEncryptedChatError");
                if ([errorType isEqual:@"USER_BLOCKED"]) {
                    errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddBlocked") : TGLocalized(@"Channel.ErrorAddBlocked");
                } else if ([errorType isEqual:@"USERS_TOO_MUCH"]) {
                    errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddTooMuch") : TGLocalized(@"Channel.ErrorAddTooMuch");
                } else if ([errorType isEqual:@"USER_NOT_MUTUAL_CONTACT"]) {
                    errorText = TGLocalized(@"Group.ErrorNotMutualContact");
                } else if ([errorType isEqual:@"ADMINS_TOO_MUCH"]) {
                    errorText = TGLocalized(@"Group.ErrorAddTooMuchAdmins");
                } else if ([errorType isEqual:@"USER_PRIVACY_RESTRICTED"]) {
                    NSString *format = conversation.isChannelGroup ? TGLocalized(@"Privacy.GroupsAndChannels.InviteToGroupError") : TGLocalized(@"Privacy.GroupsAndChannels.InviteToChannelError");
                    errorText = [[NSString alloc] initWithFormat:format, user.displayFirstName, user.displayFirstName];
                }
                [[[TGAlertView alloc] initWithTitle:nil message:errorText cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
            });
        }];
    }] startOn:[SQueue mainQueue]];
}

- (SSignal *)memberRole:(TGUser *)user {
    TGConversation *conversation = _conversation;
    
    return [[SSignal defer:^SSignal *{
        SSignal *roleSignal = [TGChannelManagementSignals channelRole:conversation.conversationId accessHash:conversation.accessHash user:user];
        
        __block TGProgressWindow *progressWindow = nil;
        
        return [[[roleSignal deliverOn:[SQueue mainQueue]] onStart:^{
            progressWindow = [[TGProgressWindow alloc] init];
            [progressWindow show:true];
        }] onDispose:^{
            TGDispatchOnMainThread(^{
                [progressWindow dismiss:true];
            });
        }];
    }] startOn:[SQueue mainQueue]];
}

- (SSignal *)addManagementMember:(TGUser *)user role:(TGChannelRole)role {
    if (user.kind == TGUserKindGeneric) {
        bool isGroup = _conversation.isChannelGroup;
        __weak TGChannelMembersController *weakSelf = self;
        return [[self memberRole:user] mapToSignal:^SSignal *(TGCachedConversationMember *member) {
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                if (member == nil) {
                    SPipe *pipe = [[SPipe alloc] init];
                    [[[TGAlertView alloc] initWithTitle:nil message:[[NSString alloc] initWithFormat:isGroup ? TGLocalized(@"Group.Management.ErrorNotMember") : TGLocalized(@"Channel.Management.ErrorNotMember"), user.displayFirstName] cancelButtonTitle:TGLocalized(@"Common.Cancel") okButtonTitle:TGLocalized(@"Common.OK") completionBlock:^(bool okButtonPressed) {
                        if (okButtonPressed) {
                            pipe.sink([[strongSelf addMember:user] then:[strongSelf modifyMemberRole:user role:role]]);
                        } else {
                            pipe.sink([SSignal fail:nil]);
                        }
                    }] show];
                    return [[pipe.signalProducer() take:1] switchToLatest];
                } else {
                    return [strongSelf modifyMemberRole:user role:role];
                }
            } else {
                return [SSignal fail:nil];
            }
        }];
    } else {
        return [self modifyMemberRole:user role:role];
    }
}

- (SSignal *)addMember:(TGUser *)user {
    __weak TGChannelMembersController *weakSelf = self;
    TGConversation *conversation = _conversation;
    
    return [[SSignal defer:^SSignal *{
        SSignal *addSignal = [[[TGChannelManagementSignals inviteUsers:conversation.conversationId accessHash:conversation.accessHash users:@[user]] onCompletion:^{
            [TGDatabaseInstance() updateChannelCachedData:conversation.conversationId block:^TGCachedConversationData *(TGCachedConversationData *data) {
                if (data == nil) {
                    data = [[TGCachedConversationData alloc] init];
                }
                
                return [data addMembers:@[@(user.uid)] timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
            }];
        }] onError:^(id error) {
            TGDispatchOnMainThread(^{
                NSString *errorType = [[TGTelegramNetworking instance] extractNetworkErrorType:error];
                NSString *errorText = TGLocalized(@"Profile.CreateEncryptedChatError");
                if ([errorType isEqual:@"USER_BLOCKED"]) {
                    errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddBlocked") : TGLocalized(@"Channel.ErrorAddBlocked");
                } else if ([errorType isEqual:@"USERS_TOO_MUCH"]) {
                    errorText = conversation.isChannelGroup ? TGLocalized(@"Group.ErrorAddTooMuch") : TGLocalized(@"Channel.ErrorAddTooMuch");
                } else if ([errorType isEqual:@"USER_NOT_MUTUAL_CONTACT"]) {
                    errorText = TGLocalized(@"Group.ErrorNotMutualContact");
                } else if ([errorType isEqual:@"ADMINS_TOO_MUCH"]) {
                    errorText = TGLocalized(@"Group.ErrorAddTooMuchAdmins");
                } else if ([errorType isEqualToString:@"USER_PRIVACY_RESTRICTED"]) {
                    NSString *format = conversation.isChannelGroup ? TGLocalized(@"Privacy.GroupsAndChannels.InviteToGroupError") : TGLocalized(@"Privacy.GroupsAndChannels.InviteToChannelError");
                    errorText = [[NSString alloc] initWithFormat:format, user.displayFirstName, user.displayFirstName];
                }
                [[[TGAlertView alloc] initWithTitle:nil message:errorText cancelButtonTitle:TGLocalized(@"Common.OK") okButtonTitle:nil completionBlock:nil] show];
            });
        }];
        
        __block TGProgressWindow *progressWindow = nil;
        
        return [[[[addSignal deliverOn:[SQueue mainQueue]] onStart:^{
            progressWindow = [[TGProgressWindow alloc] init];
            [progressWindow show:true];
        }] onDispose:^{
            TGDispatchOnMainThread(^{
                [progressWindow dismiss:true];
            });
        }] onCompletion:^{
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                if (strongSelf->_mode == TGChannelMembersModeMembers) {
                    NSMutableArray *updatedUsers = [[NSMutableArray alloc] initWithArray:strongSelf->_users];
                    [updatedUsers addObject:user];
                    NSMutableDictionary *updatedMemberDatas = [[NSMutableDictionary alloc] initWithDictionary:strongSelf->_memberDatas];
                    updatedMemberDatas[@(user.uid)] = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleMember timestamp:(int32_t)[[TGTelegramNetworking instance] approximateRemoteTime]];
                    
                    [strongSelf setUsers:updatedUsers memberDatas:updatedMemberDatas isFinal:true];
                    [strongSelf updateEditing];
                }
            }
        }];
    }] startOn:[SQueue mainQueue]];
}

- (void)selectContactControllerDidSelectUser:(TGUser *)user {
    if (user == nil) {
        [self dismissViewControllerAnimated:true completion:nil];
        return;
    }
    
    __weak TGChannelMembersController *weakSelf = self;
    if (_conversation.username.length == 0 || true) {
        [[self addManagementMember:user role:TGChannelRolePublisher] startWithNext:nil completed:^{
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                [strongSelf dismissViewControllerAnimated:true completion:nil];
            }
        }];
    } else {
        /*TGChannelModeratorController *controller = [[TGChannelModeratorController alloc] initWithConversation:_conversation user:user member:nil];
        __weak TGChannelMembersController *weakSelf = self;
        controller.done = ^(TGCachedConversationMember *member) {
            if (member == nil) {
                member = [[TGCachedConversationMember alloc] initWithUid:user.uid role:TGChannelRoleModerator timestamp:0];
            }
            
            [[self addManagementMember:user role:member.role] startWithNext:nil completed:^{
                __strong TGChannelMembersController *strongSelf = weakSelf;
                if (strongSelf != nil) {
                    [strongSelf dismissViewControllerAnimated:true completion:nil];
                }
            }];
        };
        if ([self.presentedViewController isKindOfClass:[TGNavigationController class]]) {
            [(UINavigationController *)self.presentedViewController pushViewController:controller animated:true];
        }*/
    }
}

- (void)whoCanAddMembersPressed {
    __weak TGChannelMembersController *weakSelf = self;
    [[[TGActionSheet alloc] initWithTitle:nil actions:@[
        [[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"ChannelMembers.WhoCanAddMembers.AllMembers") action:@"all"],
        [[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"ChannelMembers.WhoCanAddMembers.Admins") action:@"admins"],
        [[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]
    ] actionBlock:^(__unused id target, NSString *action) {
        __strong TGChannelMembersController *strongSelf = weakSelf;
        if (strongSelf != nil) {
            if ([action isEqualToString:@"all"]) {
                [strongSelf updateWhoCanAddMembers:true];
            } else if ([action isEqualToString:@"admins"]) {
                [strongSelf updateWhoCanAddMembers:false];
            }
        }
    } target:self] showInView:self.view];
}

- (void)updateWhoCanAddMembers:(bool)allMembers {
    if (allMembers != _conversation.everybodyCanAddMembers) {
        TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init];
        [progressWindow showWithDelay:0.2];
        __weak TGChannelMembersController *weakSelf = self;
        [[[[TGChannelManagementSignals toggleChannelEverybodyCanInviteMembers:_conversation.conversationId accessHash:_conversation.accessHash enabled:allMembers] deliverOn:[SQueue mainQueue]] onDispose:^{
            TGDispatchOnMainThread(^{
                [progressWindow dismiss:true];
            });
        }] startWithNext:nil completed:^{
            __strong TGChannelMembersController *strongSelf = weakSelf;
            if (strongSelf != nil) {
                strongSelf->_conversation.everybodyCanAddMembers = allMembers;
            }
        }];
        _inviteControlItem.variant = allMembers ? TGLocalized(@"ChannelMembers.WhoCanAddMembers.AllMembers") : TGLocalized(@"ChannelMembers.WhoCanAddMembers.Admins");
        if (allMembers) {
            _inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAllHelp");
        } else {
            _inviteControlComment.text = TGLocalized(@"ChannelMembers.WhoCanAddMembersAdminsHelp");
        }
    }
}

@end
