// Copyright 2023 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/autofill/manual_fill/ui/fallback_view_controller.h"

#import "base/apple/foundation_util.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_header_footer_item.h"
#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_controller_test.h"

namespace {

typedef NS_ENUM(NSInteger, ItemType) {
  ItemTypeSampleOne = kItemTypeEnumZero,
  ItemTypeSampleTwo,
  ItemTypeSampleThree,
  ItemTypeSampleFour
};

}  // namespace

class FallbackViewControllerTest : public LegacyChromeTableViewControllerTest {
 public:
  FallbackViewControllerTest() {}

 protected:
  void SetUp() override {
    LegacyChromeTableViewControllerTest::SetUp();
    CreateController();
    CheckController();
  }

  LegacyChromeTableViewController* InstantiateController() override {
    FallbackViewController* view_controller =
        [[FallbackViewController alloc] init];
    [view_controller loadModel];
    return view_controller;
  }

  FallbackViewController* GetFallbackViewController() {
    return base::apple::ObjCCastStrict<FallbackViewController>(controller());
  }

  // Returns the header item at `section`.
  id GetHeaderItem(int section) {
    return [controller().tableViewModel headerForSectionIndex:section];
  }

  // Returns the type of the header item at `section`.
  NSInteger GetHeaderItemType(int section) {
    return base::apple::ObjCCastStrict<TableViewHeaderFooterItem>(
               GetHeaderItem(section))
        .type;
  }

  // Returns the type of the table view item at `item` in `section`.
  NSInteger GetTableViewItemType(int section, int item) {
    return base::apple::ObjCCastStrict<TableViewItem>(
               GetTableViewItem(section, item))
        .type;
  }
};

// Tests the order of the elements in the view when all of data, action and
// header items are initialized.
TEST_F(FallbackViewControllerTest, CheckItems) {
  TableViewItem* item_one =
      [[TableViewItem alloc] initWithType:ItemTypeSampleOne];
  TableViewItem* item_two =
      [[TableViewItem alloc] initWithType:ItemTypeSampleTwo];
  NSArray<TableViewItem*>* data_items = @[ item_one, item_two ];

  TableViewItem* item_three =
      [[TableViewItem alloc] initWithType:ItemTypeSampleThree];
  NSArray<TableViewItem*>* action_items = @[ item_three ];

  TableViewHeaderFooterItem* item_four =
      [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeSampleFour];

  FallbackViewController* fallbackViewController = GetFallbackViewController();

  [fallbackViewController presentDataItems:data_items];
  [fallbackViewController presentActionItems:action_items];
  [fallbackViewController presentHeaderItem:item_four];

  // Data items each have their own section.
  EXPECT_EQ(NumberOfSections(), 4);

  // Header section stays at the top and has no items other than a header.
  EXPECT_EQ(NumberOfItemsInSection(0), 0);
  EXPECT_EQ(NumberOfItemsInSection(1), 1);
  EXPECT_EQ(NumberOfItemsInSection(2), 1);
  EXPECT_EQ(NumberOfItemsInSection(3), 1);

  EXPECT_EQ(GetHeaderItemType(/*section=*/0), ItemTypeSampleFour);
  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0), ItemTypeSampleOne);
  EXPECT_EQ(GetTableViewItemType(/*section=*/2, /*item=*/0), ItemTypeSampleTwo);
  EXPECT_EQ(GetTableViewItemType(/*section=*/3, /*item=*/0),
            ItemTypeSampleThree);
}

// Tests that unused data item sections are deleted as expected.
TEST_F(FallbackViewControllerTest, RemoveUnusedDataItemSections) {
  TableViewItem* item_one =
      [[TableViewItem alloc] initWithType:ItemTypeSampleOne];
  TableViewItem* item_two =
      [[TableViewItem alloc] initWithType:ItemTypeSampleTwo];
  TableViewItem* item_three =
      [[TableViewItem alloc] initWithType:ItemTypeSampleThree];

  FallbackViewController* fallback_view_controller =
      GetFallbackViewController();

  // Present three data items.
  [fallback_view_controller
      presentDataItems:@[ item_one, item_two, item_three ]];
  // Data items each have their own section.
  EXPECT_EQ(NumberOfSections(), 3);

  // Present 2 data items.
  [fallback_view_controller presentDataItems:@[ item_one, item_two ]];
  EXPECT_EQ(NumberOfSections(), 2);

  // Present no data items.
  [fallback_view_controller presentDataItems:@[]];
  EXPECT_EQ(NumberOfSections(), 0);
}

// Tests that the "no data items to show" message is displayed in the right
// place in the table view.
TEST_F(FallbackViewControllerTest, CheckNoDataItemsMessage) {
  FallbackViewController* fallback_view_controller =
      GetFallbackViewController();

  // Set `noRegularDataItemsToShowHeaderItem`.
  TableViewTextHeaderFooterItem* header_item =
      [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeSampleOne];
  fallback_view_controller.noRegularDataItemsToShowHeaderItem = header_item;

  TableViewItem* action_item =
      [[TableViewItem alloc] initWithType:ItemTypeSampleThree];
  NSArray<TableViewItem*>* action_items = @[ action_item ];

  [fallback_view_controller presentDataItems:@[]];
  [fallback_view_controller presentActionItems:action_items];

  // The "no data items to show" message is displayed as a header for the
  // actions section. Only the actions section and no data item section should
  // be present in the table view.
  EXPECT_EQ(NumberOfSections(), 2);

  // The actions section should have a header and an item.
  EXPECT_TRUE(GetHeaderItem(/*section=*/0));
  EXPECT_EQ(NumberOfItemsInSection(0), 0);
  EXPECT_EQ(NumberOfItemsInSection(1), 1);

  EXPECT_EQ(GetHeaderItemType(/*section=*/0), ItemTypeSampleOne);
  EXPECT_EQ(GetTableViewItemType(/*section=*/1, /*item=*/0),
            ItemTypeSampleThree);
}

// Tests that the "no data items to show" message is displayed in the right
// place in the table view even if there are no action items to show.
TEST_F(FallbackViewControllerTest, CheckNoDataItemsMessageWhenNoActions) {
  FallbackViewController* fallback_view_controller =
      GetFallbackViewController();

  // Set `noRegularDataItemsToShowHeaderItem`.
  TableViewTextHeaderFooterItem* header_item =
      [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeSampleOne];
  fallback_view_controller.noRegularDataItemsToShowHeaderItem = header_item;

  [fallback_view_controller presentDataItems:@[]];
  [fallback_view_controller presentActionItems:@[]];

  // Only the actions section should be present in the table view.
  EXPECT_EQ(NumberOfSections(), 1);

  // The actions section should only have a header.
  EXPECT_TRUE(GetHeaderItem(/*section=*/0));
  EXPECT_EQ(NumberOfItemsInSection(0), 0);

  EXPECT_EQ(GetHeaderItemType(/*section=*/0), ItemTypeSampleOne);
}
