// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/home_customization/ui/home_customization_discover_view_controller.h"

#import "base/check.h"
#import "ios/chrome/browser/home_customization/ui/home_customization_collection_configurator.h"
#import "ios/chrome/browser/home_customization/ui/home_customization_header_view.h"
#import "ios/chrome/browser/home_customization/ui/home_customization_link_cell.h"
#import "ios/chrome/browser/home_customization/ui/home_customization_mutator.h"
#import "ios/chrome/browser/home_customization/ui/home_customization_view_controller_protocol.h"
#import "ios/chrome/browser/home_customization/utils/home_customization_constants.h"

@interface HomeCustomizationDiscoverViewController () <
    HomeCustomizationViewControllerProtocol,
    UICollectionViewDelegate>

// Contains the types of HomeCustomizationLinkCells that should be shown.
@property(nonatomic, assign) std::vector<CustomizationLinkType> linksVector;

@end

@implementation HomeCustomizationDiscoverViewController {
  // The configurator for the collection view.
  HomeCustomizationCollectionConfigurator* _collectionConfigurator;

  // Registration for the HomeCustomizationLinkCell.
  UICollectionViewCellRegistration* _linkCellRegistration;

  // Registration for the collection's header.
  UICollectionViewSupplementaryRegistration* _headerRegistration;
}

// Synthesized from HomeCustomizationViewControllerProtocol.
@synthesize collectionView = _collectionView;
@synthesize diffableDataSource = _diffableDataSource;
@synthesize page = _page;
@synthesize additionalViewWillTransitionToSizeHandler =
    _additionalViewWillTransitionToSizeHandler;

- (void)viewDidLoad {
  [super viewDidLoad];

  _collectionConfigurator = [[HomeCustomizationCollectionConfigurator alloc]
      initWithViewController:self];
  _page = CustomizationMenuPage::kDiscover;

  [self registerCells];
  [_collectionConfigurator configureCollectionView];

  // Sets initial data.
  [_diffableDataSource applySnapshot:[self dataSnapshot]
                animatingDifferences:NO];

  // The primary view is set as the collection view for better integration with
  // the UISheetPresentationController which presents it.
  self.view = _collectionView;

  [_collectionConfigurator configureNavigationBar];
}

- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:
           (id<UIViewControllerTransitionCoordinator>)coordinator {
  if (_additionalViewWillTransitionToSizeHandler) {
    _additionalViewWillTransitionToSizeHandler(size, coordinator);
  }
}

#pragma mark - Private

// Registers the different cells used by the collection view.
- (void)registerCells {
  __weak __typeof(self) weakSelf = self;
  _linkCellRegistration = [UICollectionViewCellRegistration
      registrationWithCellClass:[HomeCustomizationLinkCell class]
           configurationHandler:^(HomeCustomizationLinkCell* cell,
                                  NSIndexPath* indexPath,
                                  NSString* itemIdentifier) {
             CustomizationLinkType linkType =
                 (CustomizationLinkType)[itemIdentifier integerValue];
             [cell configureCellWithType:linkType];
             cell.mutator = weakSelf.mutator;
           }];

  _headerRegistration = [UICollectionViewSupplementaryRegistration
      registrationWithSupplementaryClass:[HomeCustomizationHeaderView class]
                             elementKind:UICollectionElementKindSectionHeader
                    configurationHandler:^(HomeCustomizationHeaderView* header,
                                           NSString* elementKind,
                                           NSIndexPath* indexPath) {
                      header.page = CustomizationMenuPage::kDiscover;
                    }];
}

// Creates a data snapshot representing the content of the collection view.
- (NSDiffableDataSourceSnapshot<CustomizationSection*, NSString*>*)
    dataSnapshot {
  NSDiffableDataSourceSnapshot<CustomizationSection*, NSString*>* snapshot =
      [[NSDiffableDataSourceSnapshot alloc] init];

  // Create links section and add items to it.
  [snapshot
      appendSectionsWithIdentifiers:@[ kCustomizationSectionDiscoverLinks ]];
  [snapshot
      appendItemsWithIdentifiers:[self
                                     identifiersForLinksVector:self.linksVector]
       intoSectionWithIdentifier:kCustomizationSectionDiscoverLinks];

  return snapshot;
}

#pragma mark - HomeCustomizationViewControllerProtocol

- (void)dismissCustomizationMenuPage {
  [self.mutator dismissMenuPage];
}

- (NSCollectionLayoutSection*)
      sectionForIndex:(NSInteger)sectionIndex
    layoutEnvironment:(id<NSCollectionLayoutEnvironment>)layoutEnvironment {
  if (sectionIndex ==
      [self.diffableDataSource.snapshot
          indexOfSectionIdentifier:kCustomizationSectionDiscoverLinks]) {
    return [_collectionConfigurator
        verticalListSectionForLayoutEnvironment:layoutEnvironment];
  }
  return nil;
}

- (UICollectionViewCell*)configuredCellForIndexPath:(NSIndexPath*)indexPath
                                     itemIdentifier:(NSString*)itemIdentifier {
  return [_collectionView
      dequeueConfiguredReusableCellWithRegistration:_linkCellRegistration
                                       forIndexPath:indexPath
                                               item:itemIdentifier];
}

// Returns a configured header for the given path in the collection view.
- (UICollectionViewCell*)configuredHeaderForIndexPath:(NSIndexPath*)indexPath {
  return [_collectionView
      dequeueConfiguredReusableSupplementaryViewWithRegistration:
          _headerRegistration
                                                    forIndexPath:indexPath];
}

#pragma mark - HomeCustomizationDiscoverConsumer

- (void)populateDiscoverLinks:(std::vector<CustomizationLinkType>)linksVector {
  _linksVector = linksVector;

  // Recreate the snapshot with the new items to take into account all the
  // changes of items presence (add/remove).
  NSDiffableDataSourceSnapshot<CustomizationSection*, NSString*>* snapshot =
      [self dataSnapshot];

  // Reconfigure all present items to ensure that they are updated in case
  // their content changed.
  [snapshot reconfigureItemsWithIdentifiers:
                [self identifiersForLinksVector:linksVector]];

  [_diffableDataSource applySnapshot:snapshot animatingDifferences:YES];
}

#pragma mark - Helpers

// Returns an array of identifiers for a vector of link types, which can be
// used by the snapshot.
- (NSMutableArray<NSString*>*)identifiersForLinksVector:
    (std::vector<CustomizationLinkType>)types {
  NSMutableArray<NSString*>* linkDataIdentifiers =
      [[NSMutableArray alloc] init];
  for (auto const& type : types) {
    [linkDataIdentifiers addObject:[@((int)type) stringValue]];
  }
  return linkDataIdentifiers;
}

@end
