text: #import "TGCacheController.h"
  
  #import <LegacyComponents/LegacyComponents.h>
  
  #import "TGButtonCollectionItem.h"
  #import "TGVariantCollectionItem.h"
  #import "TGCommentCollectionItem.h"
  
  #import <LegacyComponents/TGProgressWindow.h>
  
  #import <LegacyComponents/TGRemoteImageView.h>
  
  #import "TGCustomActionSheet.h"
  
  #import "TGDatabase.h"
  
  #import "TGAppDelegate.h"
  
  #import "TGMediaCacheIndexData.h"
  
  #import "TGCachePeerItem.h"
  
  #import "TGShareSheetWindow.h"
  #import "TGAttachmentSheetCheckmarkVariantItemView.h"
  #import "TGShareSheetButtonItemView.h"
  #import "TGHeaderCollectionItem.h"
  
  #import "TGProgressAlert.h"
  
  #import "TGCacheIndexingItem.h"
  
  #import "TGPresentation.h"
  
  @interface TGEvaluatedPeerMediaCacheIndexDataWithPeer: NSObject
  
  @property (nonatomic, strong) TGEvaluatedPeerMediaCacheIndexData *data;
  @property (nonatomic, strong, readonly) id peer;
  
  @end
  
  @implementation TGEvaluatedPeerMediaCacheIndexDataWithPeer
  
  - (instancetype)initWithData:(TGEvaluatedPeerMediaCacheIndexData *)data peer:(id)peer {
      self = [super init];
      if (self != nil) {
          _data = data;
          _peer = peer;
      }
      return self;
  }
  
  @end
  
  @interface TGCacheController ()
  {
      TGProgressWindow *_progressWindow;
      TGVariantCollectionItem *_cacheItem;
      
      TGVariantCollectionItem *_clearCacheItem;
      
      NSArray *_sortedEvaluatedPeersAndData;
      int64_t _totalSize;
      TGCollectionMenuSection *_evaluatedPeersSection;
      
      id<SDisposable> _diskCacheStatsDisposable;
      TGShareSheetWindow *_attachmentSheetWindow;
      TGProgressAlert *_progressAlert;
      
      SMetaDisposable *_clearDisposable;
  }
  
  @end
  
  @implementation TGCacheController
  
  - (NSArray *)keepMediaVariants
  {
      NSArray *values = @[//@(1 * 60 * 60 * 24),
                          @(1 * 60 * 60 * 24 * 3),
                          @(1 * 60 * 60 * 24 * 7),
                          @(1 * 60 * 60 * 24 * 7 * 4),
                          @(INT_MAX)];
      
      NSMutableArray *variants = [[NSMutableArray alloc] init];
      for (NSNumber *nValue in values)
      {
          NSString *title = @"";
          
          if ([nValue intValue] == INT_MAX)
              title = TGLocalized(@"MessageTimer.Forever");
          else
              title = [TGStringUtils stringForMessageTimerSeconds:[nValue intValue]];
          
          [variants addObject:@{@"title": title, @"value": nValue}];
      }
      
      return variants;
  }
  
  - (NSString *)keepMediaVariantTitleForSeconds:(int)seconds
  {
      for (NSDictionary *record in [self keepMediaVariants])
      {
          if ([record[@"value"] intValue] == seconds)
              return record[@"title"];
      }
      
      return [[NSString alloc] initWithFormat:@"%d seconds", seconds];
  }
  
  - (instancetype)init
  {
      self = [super init];
      if (self != nil)
      {
          self.title = TGLocalized(@"Cache.Title");
          
          int keepMediaSeconds = INT_MAX;
          NSNumber *nKeepMediaSeconds = [[NSUserDefaults standardUserDefaults] objectForKey:@"keepMediaSeconds"];
          if (nKeepMediaSeconds != nil)
              keepMediaSeconds = [nKeepMediaSeconds intValue];
          
          _cacheItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"Cache.KeepMedia") action:@selector(keepMediaPressed)];
          _cacheItem.variant = [self keepMediaVariantTitleForSeconds:keepMediaSeconds];
          
          _cacheItem.deselectAutomatically = true;
          
          TGCommentCollectionItem *commentItem = [[TGCommentCollectionItem alloc] initWithFormattedText:TGLocalized(@"Cache.Help")];
          
          TGCollectionMenuSection *cacheSection = [[TGCollectionMenuSection alloc] initWithItems:@[
              _cacheItem,
              commentItem,
          ]];
          
          UIEdgeInsets topSectionInsets = cacheSection.insets;
          topSectionInsets.top = 32.0f;
          cacheSection.insets = topSectionInsets;
          [self.menuSections addSection:cacheSection];
  
          _clearCacheItem = [[TGVariantCollectionItem alloc] initWithTitle:TGLocalized(@"Cache.ClearCache") variant:@"" action:@selector(clearCachePressed)];
          _clearCacheItem.deselectAutomatically = true;
          TGCollectionMenuSection *clearSection = [[TGCollectionMenuSection alloc] initWithItems:@[
              _clearCacheItem
          ]];
          [self.menuSections addSection:clearSection];
          
          _evaluatedPeersSection = [[TGCollectionMenuSection alloc] initWithItems:@[]];
          [self.menuSections addSection:_evaluatedPeersSection];
          
          [self setSortedDataWithPeers:@[] totalSize:0 inProgress:true];
          
          __weak TGCacheController *weakSelf = self;
          _diskCacheStatsDisposable = [[[[TGDatabaseInstance() evaluatedDiskCacheStats] map:^id(TGEvaluatedMediaCacheIndexData *data) {
              NSMutableArray *sortedDataWithPeers = [[NSMutableArray alloc] init];
              
              NSMutableDictionary *migratedChannelGroupEntries = [[NSMutableDictionary alloc] init];
              NSMutableDictionary *migratedGroupMapping = [[NSMutableDictionary alloc] init];
              
              [data.dataByPeerId enumerateKeysAndObjectsUsingBlock:^(NSNumber *nPeerId, TGEvaluatedPeerMediaCacheIndexData *peerData, __unused BOOL *stop) {
                  int64_t peerId = [nPeerId longLongValue];
                  
                  bool isMigratedChannelGroupEntry = false;
                  
                  id peer = nil;
                  if (TGPeerIdIsChannel(peerId) || TGPeerIdIsGroup(peerId) || peerId < 0) {
                      TGConversation *conversation = [TGDatabaseInstance() loadConversationWithId:peerId];
                      if (conversation != nil) {
                          if (conversation.isEncrypted) {
                              conversation = [conversation copy];
                              int32_t userId = 0;
                              if (conversation.chatParticipants.chatParticipantUids.count != 0)
                                  userId = [conversation.chatParticipants.chatParticipantUids[0] intValue];
                              TGUser *user = [TGDatabaseInstance() loadUser:userId];
                              if (user != nil) {
                                  peer = conversation;
                                  conversation.additionalProperties = @{@"user": user};
                              }
                          } else {
                              if (conversation.isChannelGroup) {
                                  isMigratedChannelGroupEntry = true;
                                  TGCachedConversationData *cachedData = [TGDatabaseInstance() _channelCachedDataSync:conversation.conversationId];
                                  if (cachedData.migrationData.peerId != 0) {
                                      migratedGroupMapping[@(cachedData.migrationData.peerId)] = @(conversation.conversationId);
                                  }
                              } else if (conversation.migratedToChannelId != 0) {
                                  migratedGroupMapping[@(conversation.conversationId)] = @(TGPeerIdFromChannelId(conversation.migratedToChannelId));
                              }
                              peer = conversation;
                          }
                      }
                  } else {
                      TGUser *user = [TGDatabaseInstance() loadUser:(int32_t)peerId];
                      if (user != nil) {
                          peer = user;
                      }
                  }
                  
                  if (peer != nil) {
                      TGEvaluatedPeerMediaCacheIndexDataWithPeer *currentItem = [[TGEvaluatedPeerMediaCacheIndexDataWithPeer alloc] initWithData:peerData peer:peer];
                      
                      if (isMigratedChannelGroupEntry) {
                          migratedChannelGroupEntries[@(currentItem.data.peerId)] = currentItem;
                      }
                      
                      [sortedDataWithPeers addObject:currentItem];
                  }
              }];
              
              NSInteger count = sortedDataWithPeers.count;
              for (NSInteger i = 0; i < count; i++) {
                  TGEvaluatedPeerMediaCacheIndexDataWithPeer *item = sortedDataWithPeers[i];
                  if ([item.peer isKindOfClass:[TGConversation class]] && migratedGroupMapping[@(((TGConversation *)item.peer).conversationId)] != nil) {
                      int64_t migratedId = [migratedGroupMapping[@(((TGConversation *)item.peer).conversationId)] longLongValue];
                      TGEvaluatedPeerMediaCacheIndexDataWithPeer *entry = migratedChannelGroupEntries[@(migratedId)];
                      if (entry != nil) {
                          NSMutableDictionary *mergedItemsByType = [[NSMutableDictionary alloc] init];
                          NSMutableDictionary *mergedTotalSizeByType = [[NSMutableDictionary alloc] init];
                          int64_t mergedTotalSize = 0;
                          
                          [entry.data.itemsByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSArray *items, __unused BOOL *stop) {
                              NSMutableArray *array = mergedItemsByType[nType];
                              if (array == nil) {
                                  array = [[NSMutableArray alloc] init];
                                  mergedItemsByType[nType] = array;
                              }
                              [array addObjectsFromArray:items];
                          }];
                          
                          [item.data.itemsByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSArray *items, __unused BOOL *stop) {
                              NSMutableArray *array = mergedItemsByType[nType];
                              if (array == nil) {
                                  array = [[NSMutableArray alloc] init];
                                  mergedItemsByType[nType] = array;
                              }
                              [array addObjectsFromArray:items];
                          }];
                          
                          [entry.data.totalSizeByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSNumber *nSize, __unused BOOL *stop) {
                              mergedTotalSizeByType[nType] = @([mergedTotalSizeByType[nType] longLongValue] + [nSize longLongValue]);
                          }];
                          
                          [item.data.totalSizeByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSNumber *nSize, __unused BOOL *stop) {
                              mergedTotalSizeByType[nType] = @([mergedTotalSizeByType[nType] longLongValue] + [nSize longLongValue]);
                          }];
                          
                          mergedTotalSize = entry.data.totalSize + item.data.totalSize;
                          
                          entry.data = [[TGEvaluatedPeerMediaCacheIndexData alloc] initWithPeerId:entry.data.peerId itemsByType:mergedItemsByType totalSizeByType:mergedTotalSizeByType totalSize:mergedTotalSize];
                          
                          [sortedDataWithPeers removeObjectAtIndex:i];
                          i--;
                          count--;
                      }
                  }
              }
              
              [sortedDataWithPeers sortUsingComparator:^NSComparisonResult(TGEvaluatedPeerMediaCacheIndexDataWithPeer *item1, TGEvaluatedPeerMediaCacheIndexDataWithPeer *item2) {
                  return item1.data.totalSize < item2.data.totalSize ? NSOrderedDescending : NSOrderedAscending;
              }];
              
              int64_t sortedDataTotalSize = 0;
              NSInteger index = -1;
              for (TGEvaluatedPeerMediaCacheIndexDataWithPeer *item in sortedDataWithPeers) {
                  index++;
                  if (item.data.totalSize < 100 * 1024) {
                      [sortedDataWithPeers removeObjectsInRange:NSMakeRange(index, sortedDataWithPeers.count - index)];
                      break;
                  } else {
                      sortedDataTotalSize += item.data.totalSize;
                  }
              }
              
              return @{@"sortedDataWithPeers": sortedDataWithPeers, @"totalSize": @(sortedDataTotalSize)};
          }] deliverOn:[SQueue mainQueue]] startWithNext:^(NSDictionary *dict) {
              __strong TGCacheController *strongSelf = weakSelf;
              if (strongSelf != nil) {
                  [strongSelf setSortedDataWithPeers:dict[@"sortedDataWithPeers"] totalSize:[dict[@"totalSize"] longLongValue] inProgress:false];
              }
          }];
      }
      return self;
  }
  
  - (void)dealloc {
      [_diskCacheStatsDisposable dispose];
      [_clearDisposable dispose];
      
      [_attachmentSheetWindow dismissAnimated:false completion:nil];
  }
  
  - (void)keepMediaPressed
  {
      __weak TGCacheController *weakSelf = self;
      
      NSMutableArray *actions = [[NSMutableArray alloc] init];
      for (NSDictionary *record in [self keepMediaVariants])
      {
          [actions addObject:[[TGActionSheetAction alloc] initWithTitle:record[@"title"] action:[[NSString alloc] initWithFormat:@"%@", record[@"value"]]]];
      }
      [actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]];
      
      [[[TGCustomActionSheet alloc] initWithTitle:nil actions:actions actionBlock:^(__unused id target, NSString *action)
      {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil)
          {
             if (![action isEqualToString:@"cancel"])
             {
                 [strongSelf applyKeepMediaSeconds:[action intValue]];
             }
          }
      } target:self] showInView:self.view];
  }
  
  - (void)applyKeepMediaSeconds:(int)value
  {
      [[NSUserDefaults standardUserDefaults] setObject:@(value) forKey:@"keepMediaSeconds"];
      [[NSUserDefaults standardUserDefaults] synchronize];
      
      [_cacheItem setVariant:[self keepMediaVariantTitleForSeconds:value]];
      
      [TGDatabaseInstance() processAndScheduleMediaCleanup];
  }
  
  - (void)showClearCacheSheet:(NSDictionary *)evaluatedSizeByType clear:(void (^)(NSArray *types))clear {
      [_attachmentSheetWindow dismissAnimated:true completion:nil];
      
      __weak TGCacheController *weakSelf = self;
      _attachmentSheetWindow = [[TGShareSheetWindow alloc] init];
      _attachmentSheetWindow.dismissalBlock = ^
      {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf == nil)
              return;
          
          strongSelf->_attachmentSheetWindow.rootViewController = nil;
          strongSelf->_attachmentSheetWindow = nil;
      };
      
      NSMutableArray *items = [[NSMutableArray alloc] init];
      
      int32_t cacheSizeThreshold = 1;
      NSMutableSet *checkedTypes = [[NSMutableSet alloc] initWithArray:@[@(TGMediaCacheItemTypeImage), @(TGMediaCacheItemTypeVideo), @(TGMediaCacheItemTypeMusic), @(TGMediaCacheItemTypeFile)]];
      
      TGShareSheetButtonItemView *clearButtonItem = [[TGShareSheetButtonItemView alloc] initWithTitle:@"" pressed:^ {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil) {
              [strongSelf->_attachmentSheetWindow dismissAnimated:true completion:nil];
              strongSelf->_attachmentSheetWindow = nil;
              
              if (clear) {
                  clear([checkedTypes allObjects]);
              }
          }
      }];
      
      void (^updateCheckedTypes)() = ^{
          __block int64_t totalSize = 0;
          [evaluatedSizeByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSNumber *nSize, __unused BOOL *stop) {
              if ([checkedTypes containsObject:nType]) {
                  totalSize += [nSize longLongValue];
              }
          }];
          if (totalSize > 0) {
              [clearButtonItem setTitle:[[NSString alloc] initWithFormat:TGLocalized(@"Cache.Clear"), [TGStringUtils stringForFileSize:totalSize]]];
              //[clearButtonItem setDisabled:false];
          } else {
              [clearButtonItem setTitle:TGLocalized(@"Cache.ClearNone")];
              //[clearButtonItem setDisabled:true];
          }
      };
      
      updateCheckedTypes();
      
      NSArray *possibleTypes = @[@(TGMediaCacheItemTypeImage), @(TGMediaCacheItemTypeVideo), @(TGMediaCacheItemTypeMusic), @(TGMediaCacheItemTypeFile)];
      NSDictionary *typeTitles = @{@(TGMediaCacheItemTypeImage): TGLocalized(@"Cache.Photos"), @(TGMediaCacheItemTypeVideo): TGLocalized(@"Cache.Videos"), @(TGMediaCacheItemTypeMusic): TGLocalized(@"Cache.Music"), @(TGMediaCacheItemTypeFile): TGLocalized(@"Cache.Files")};
      
      for (NSNumber *nType in possibleTypes) {
          if ([evaluatedSizeByType[nType] longLongValue] >= cacheSizeThreshold) {
              TGAttachmentSheetCheckmarkVariantItemView *itemView = [[TGAttachmentSheetCheckmarkVariantItemView alloc] initWithTitle:typeTitles[nType] variant:[TGStringUtils stringForFileSize:[evaluatedSizeByType[nType] longLongValue]] checked:true];
              itemView.onCheckedChanged = ^(bool value) {
                  if (value) {
                      [checkedTypes addObject:nType];
                  } else {
                      [checkedTypes removeObject:nType];
                  }
                  updateCheckedTypes();
              };
              [items addObject:itemView];
          }
      }
      
      [items addObject:clearButtonItem];
      
      _attachmentSheetWindow.view.cancel = ^{
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil) {
              [strongSelf->_attachmentSheetWindow dismissAnimated:true completion:nil];
              strongSelf->_attachmentSheetWindow = nil;
          }
      };
      
      _attachmentSheetWindow.view.items = items;
      [_attachmentSheetWindow showAnimated:true completion:nil];
  }
  
  - (void)clearCachePressed
  {
      NSMutableDictionary *itemsByType = [[NSMutableDictionary alloc] init];
      NSMutableDictionary *totalSizeByType = [[NSMutableDictionary alloc] init];
      int64_t totalSize = 0;
      
      for (TGEvaluatedPeerMediaCacheIndexDataWithPeer *peerData in _sortedEvaluatedPeersAndData) {
          [peerData.data.itemsByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSArray *items, __unused BOOL *stop) {
              NSMutableArray *array = itemsByType[nType];
              if (array == nil) {
                  array = [[NSMutableArray alloc] init];
                  itemsByType[nType] = array;
              }
              [array addObjectsFromArray:items];
          }];
          [peerData.data.totalSizeByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSNumber *nSize, __unused BOOL *stop) {
              totalSizeByType[nType] = @([totalSizeByType[nType] longLongValue] + [nSize longLongValue]);
          }];
          totalSize += peerData.data.totalSize;
      }
      
      TGEvaluatedPeerMediaCacheIndexData *data = [[TGEvaluatedPeerMediaCacheIndexData alloc] initWithPeerId:0 itemsByType:itemsByType totalSizeByType:totalSizeByType totalSize:totalSize];
      
      __weak TGCacheController *weakSelf = self;
      [self showClearCacheSheet:totalSizeByType clear:^(NSArray *types) {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil) {
              [strongSelf clearPeerData:data types:types];
          }
      }];
  }
  
  - (void)setSortedDataWithPeers:(NSArray *)sortedDataWithPeers totalSize:(int64_t)totalSize inProgress:(bool)inProgress {
      _sortedEvaluatedPeersAndData = sortedDataWithPeers;
      _totalSize = totalSize;
      
      if (inProgress) {
          _clearCacheItem.variant = @"";
          _clearCacheItem.enabled = false;
      } else {
          if (totalSize == 0) {
              _clearCacheItem.variant = TGLocalized(@"Cache.ClearEmpty");
              _clearCacheItem.enabled = false;
          } else {
              _clearCacheItem.variant = [TGStringUtils stringForFileSize:totalSize];
              _clearCacheItem.enabled = true;
          }
      }
      
      while (_evaluatedPeersSection.items.count != 0) {
          [_evaluatedPeersSection deleteItemAtIndex:0];
      }
      
      if (inProgress || sortedDataWithPeers.count != 0) {
          [_evaluatedPeersSection addItem:[[TGHeaderCollectionItem alloc] initWithTitle:TGLocalized(@"Cache.ByPeerHeader")]];
      }
      
      __weak TGCacheController *weakSelf = self;
      void (^onSelected)(TGEvaluatedPeerMediaCacheIndexData *) = ^(TGEvaluatedPeerMediaCacheIndexData *peerData) {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil) {
              [strongSelf showClearCacheSheet:peerData.totalSizeByType clear:^(NSArray *types) {
                  __strong TGCacheController *strongSelf = weakSelf;
                  if (strongSelf != nil) {
                      [strongSelf clearPeerData:peerData types:types];
                  }
              }];
          }
      };
      for (TGEvaluatedPeerMediaCacheIndexDataWithPeer *item in sortedDataWithPeers) {
          TGCachePeerItem *cacheItem = [[TGCachePeerItem alloc] initWithPeer:item.peer evaluatedPeerData:item.data];
          cacheItem.onSelected = onSelected;
          [_evaluatedPeersSection addItem:cacheItem];
      }
      
      if (inProgress) {
          [_evaluatedPeersSection addItem:[[TGCacheIndexingItem alloc] init]];
      }
      
      [self.collectionView reloadData];
  }
  
  - (void)clearPeerData:(TGEvaluatedPeerMediaCacheIndexData *)peerData types:(NSArray *)types {
      __weak TGCacheController *weakSelf = self;
      
      _progressAlert = [[TGProgressAlert alloc] initWithFrame:self.view.bounds backgroundColor:self.presentation.pallete.menuBackgroundColor separatorColor:self.presentation.pallete.menuSeparatorColor textColor:self.presentation.pallete.menuTextColor accentColor:self.presentation.pallete.menuAccentColor];
      _progressAlert.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
      _progressAlert.text = TGLocalized(@"Cache.ClearProgress");
      _progressAlert.alpha = 0.0f;
      [self.view addSubview:_progressAlert];
      [UIView animateWithDuration:0.3 animations:^
      {
          _progressAlert.alpha = 1.0f;
      }];
      
      _progressAlert.cancel = ^
      {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil)
          {
              [strongSelf->_clearDisposable setDisposable:nil];
              
              [UIView animateWithDuration:0.3 animations:^
              {
                  strongSelf->_progressAlert.alpha = 0.0f;
              } completion:^(__unused BOOL finished)
              {
                  [strongSelf->_progressAlert removeFromSuperview];
                  strongSelf->_progressAlert = nil;
              }];
          }
      };
      
      SSignal *clearSignal = [[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
          __block bool cancelled = false;
          
          [[[SQueue alloc] init] dispatch:^{
              NSMutableArray *filePaths = [[NSMutableArray alloc] init];
              [peerData.itemsByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSArray *items, BOOL *stop) {
                  if ([types containsObject:nType]) {
                      for (TGEvaluatedCacheItem *item in items) {
                          [filePaths addObjectsFromArray:item.filePaths];
                      }
                  }
                  
                  *stop = cancelled;
              }];
              
              NSArray *tmpFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:NSTemporaryDirectory() error:nil];
              for (NSString *path in tmpFiles) {
                  [filePaths addObject:[NSTemporaryDirectory() stringByAppendingPathComponent:path]];
              }
              
              if (!cancelled) {
                  int32_t counter = 0;
                  int32_t totalCount = (int32_t)filePaths.count;
                  for (NSString *filePath in filePaths) {
                      if (counter++ % 20 == 0) {
                          if (cancelled) {
                              break;
                          } else {
                              [subscriber putNext:@(MIN(1.0, ((float)counter) / totalCount))];
                          }
                      }
                      
                      unlink([filePath UTF8String]);
                  }
              }
              
              [subscriber putNext:@(1.0f)];
              
              [subscriber putCompletion];
          }];
          
          return [[SBlockDisposable alloc] initWithBlock:^{
              cancelled = true;
          }];
      }] then:[[SSignal complete] delay:0.8 onQueue:[SQueue mainQueue]]];
      
      id<SDisposable> clearDisposable = [[clearSignal deliverOn:[SQueue mainQueue]] startWithNext:^(NSNumber *nProgress) {
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil) {
              [strongSelf->_progressAlert setProgress:[nProgress floatValue] animated:true];
          }
      } completed:^{
          __strong TGCacheController *strongSelf = weakSelf;
          if (strongSelf != nil) {
              if (peerData.peerId == 0) {
                  NSMutableArray *filteredDataWithPeers = [[NSMutableArray alloc] init];
                  int64_t filteredTotalSize = strongSelf->_totalSize;
                  for (TGEvaluatedPeerMediaCacheIndexDataWithPeer *item in strongSelf->_sortedEvaluatedPeersAndData) {
                      __block int64_t filteredItemsTotalSize = 0;
                      NSMutableDictionary *filteredItemsByType = [[NSMutableDictionary alloc] initWithDictionary:item.data.itemsByType];
                      NSMutableDictionary *filteredTotalSizeByType = [[NSMutableDictionary alloc] initWithDictionary:item.data.totalSizeByType];
                      
                      [item.data.totalSizeByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSNumber *nSize, __unused BOOL *stop) {
                          if (![types containsObject:nType]) {
                              filteredItemsTotalSize += [nSize longLongValue];
                          } else {
                              [filteredItemsByType removeObjectForKey:nType];
                              [filteredTotalSizeByType removeObjectForKey:nType];
                          }
                      }];
                      if (filteredItemsTotalSize >= 100 * 1024) {
                          filteredTotalSize = MAX(0, filteredTotalSize + filteredItemsTotalSize - item.data.totalSize);
                          [filteredDataWithPeers addObject:[[TGEvaluatedPeerMediaCacheIndexDataWithPeer alloc] initWithData:[[TGEvaluatedPeerMediaCacheIndexData alloc] initWithPeerId:item.data.peerId itemsByType:filteredItemsByType totalSizeByType:filteredTotalSizeByType totalSize:filteredItemsTotalSize] peer:item.peer]];
                      } else {
                          filteredTotalSize = MAX(0, filteredTotalSize - item.data.totalSize);
                      }
                  }
                  
                  [strongSelf setSortedDataWithPeers:filteredDataWithPeers totalSize:filteredTotalSize inProgress:false];
              } else {
                  NSMutableArray *filteredDataWithPeers = [[NSMutableArray alloc] init];
                  int64_t filteredTotalSize = strongSelf->_totalSize;
                  NSInteger index = -1;
                  int64_t peerId = peerData.peerId;
                  for (TGEvaluatedPeerMediaCacheIndexDataWithPeer *item in strongSelf->_sortedEvaluatedPeersAndData) {
                      index++;
                      if (item.data.peerId == peerId) {
                          __block int64_t filteredItemsTotalSize = 0;
                          NSMutableDictionary *filteredItemsByType = [[NSMutableDictionary alloc] initWithDictionary:item.data.itemsByType];
                          NSMutableDictionary *filteredTotalSizeByType = [[NSMutableDictionary alloc] initWithDictionary:item.data.totalSizeByType];
                          
                          [item.data.totalSizeByType enumerateKeysAndObjectsUsingBlock:^(NSNumber *nType, NSNumber *nSize, __unused BOOL *stop) {
                              if (![types containsObject:nType]) {
                                  filteredItemsTotalSize += [nSize longLongValue];
                              } else {
                                  [filteredItemsByType removeObjectForKey:nType];
                                  [filteredTotalSizeByType removeObjectForKey:nType];
                              }
                          }];
                          filteredTotalSize = MAX(0, filteredTotalSize + filteredItemsTotalSize - item.data.totalSize);
                          if (filteredItemsTotalSize >= 100 * 1024) {
                              [filteredDataWithPeers addObject:[[TGEvaluatedPeerMediaCacheIndexDataWithPeer alloc] initWithData:[[TGEvaluatedPeerMediaCacheIndexData alloc] initWithPeerId:item.data.peerId itemsByType:filteredItemsByType totalSizeByType:filteredTotalSizeByType totalSize:filteredItemsTotalSize] peer:item.peer]];
                          }
                      } else {
                          [filteredDataWithPeers addObject:item];
                      }
                  }
                  
                  [filteredDataWithPeers sortUsingComparator:^NSComparisonResult(TGEvaluatedPeerMediaCacheIndexDataWithPeer *item1, TGEvaluatedPeerMediaCacheIndexDataWithPeer *item2) {
                      return item1.data.totalSize < item2.data.totalSize ? NSOrderedDescending : NSOrderedAscending;
                  }];
                  
                  [strongSelf setSortedDataWithPeers:filteredDataWithPeers totalSize:filteredTotalSize inProgress:false];
              }
              
              [UIView animateWithDuration:0.3 animations:^ {
                  strongSelf->_progressAlert.alpha = 0.0f;
              } completion:^(__unused BOOL finished) {
                  [strongSelf->_progressAlert removeFromSuperview];
                  strongSelf->_progressAlert = nil;
              }];
          }
      }];
      
      if (_clearDisposable == nil) {
          _clearDisposable = [[SMetaDisposable alloc] init];
      }
      [_clearDisposable setDisposable:clearDisposable];
  }
  
  @end
  