// 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 "base/strings/sys_string_conversions.h"
#import "components/policy/policy_constants.h"
#import "components/regional_capabilities/regional_capabilities_switches.h"
#import "components/regional_capabilities/regional_capabilities_test_utils.h"
#import "components/search_engines/search_engine_choice/search_engine_choice_utils.h"
#import "components/search_engines/search_engines_switches.h"
#import "components/strings/grit/components_strings.h"
#import "google_apis/gaia/core_account_id.h"
#import "ios/chrome/browser/authentication/test/signin_earl_grey.h"
#import "ios/chrome/browser/authentication/test/signin_matchers.h"
#import "ios/chrome/browser/first_run/public/features.h"
#import "ios/chrome/browser/first_run/test/first_run_app_interface.h"
#import "ios/chrome/browser/first_run/test/first_run_test_case_base.h"
#import "ios/chrome/browser/metrics/model/metrics_app_interface.h"
#import "ios/chrome/browser/policy/model/policy_earl_grey_utils.h"
#import "ios/chrome/browser/search_engine_choice/test/search_engine_choice_earl_grey_ui_test_util.h"
#import "ios/chrome/browser/search_engine_choice/ui/search_engine_choice_constants.h"
#import "ios/chrome/browser/settings/ui_bundled/settings_app_interface.h"
#import "ios/chrome/browser/settings/ui_bundled/settings_table_view_controller_constants.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/common/ui/promo_style/constants.h"
#import "ios/chrome/test/earl_grey/chrome_actions.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "third_party/search_engines_data/resources/definitions/prepopulated_engines.h"
#import "ui/base/l10n/l10n_util_mac.h"

// Tests first run stages with search engine choice
@interface FirstRunSearchEngineChoiceTestCase : FirstRunTestCaseBase
@end

@implementation FirstRunSearchEngineChoiceTestCase

- (AppLaunchConfiguration)appConfigurationForTestCase {
  AppLaunchConfiguration config = [super appConfigurationForTestCase];
  config.features_disabled.push_back(kAuthenticationFlowReauthFirstKillswitch);
  // Need to use `switches::kEeaListCountryOverride` as the country to list all
  // the search engines. This is to make sure the more button appears.
  config.additional_args.push_back(
      "--" + std::string(switches::kSearchEngineChoiceCountry) + "=" +
      switches::kEeaListCountryOverride);
  config.additional_args.push_back(
      "--" + std::string(switches::kForceSearchEngineChoiceScreen));
  config.additional_args.push_back("true");
  // Enable the updated FRE sequence variation 2 (kRemoveSignInSync) to verify
  // that the standard sequence is displayed when a choice screen is required.
  config.features_enabled_and_params.push_back(
      {first_run::kUpdatedFirstRunSequence,
       {{first_run::kUpdatedFirstRunSequenceParam, "2"}}});
  // Disable the animated default browser promo to prevent post-FRE promotions
  // from interfering with the settings verification steps.
  config.features_disabled.push_back(
      first_run::kAnimatedDefaultBrowserPromoInFRE);

  if ([self isRunningTest:@selector
            (testNoDefaultBrowserPromoAfterSearchEngineChoiceScreen)]) {
    config.features_enabled.push_back(
        first_run::kSkipDefaultBrowserPromoInFirstRun);
  } else {
    config.features_disabled.push_back(
        first_run::kSkipDefaultBrowserPromoInFirstRun);
  }

  return config;
}

- (void)setUp {
  [super setUp];
  // Make sure the search engine has been reset, to avoid any issues if it was
  // not by a previous test.
  [SettingsAppInterface resetSearchEngine];
}

- (void)tearDownHelper {
  // Reset the search engine for any other tests.
  [SettingsAppInterface resetSearchEngine];
  [super tearDownHelper];
}

#pragma mark - Tests

// Tests that the Search Engine Choice screen is displayed, that the primary
// button is correctly updated when the user selects a search engine then
// scrolls down and that it correctly sets the default search engine.
- (void)testSearchEngineChoiceScreenSelectThenScroll {
  // Skip sign-in.
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackSecondaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];
  // Check that the choice screen is shown
  [SearchEngineChoiceEarlGreyUI verifySearchEngineChoiceScreenIsDisplayed];
  // Verify that the primary button is initially the "More" pill button.
  id<GREYMatcher> moreButtonMatcher =
      grey_accessibilityID(kSearchEngineMoreButtonIdentifier);
  [[EarlGrey selectElementWithMatcher:moreButtonMatcher]
      assertWithMatcher:grey_allOf(grey_enabled(), grey_notNil(), nil)];
  // Select a search engine.
  NSString* searchEngineToSelect = [SearchEngineChoiceEarlGreyUI
      searchEngineNameWithPrepopulatedEngine:TemplateURLPrepopulateData::bing];
  [SearchEngineChoiceEarlGreyUI
      selectSearchEngineCellWithName:searchEngineToSelect
                     scrollDirection:kGREYDirectionDown
                              amount:50];
  // Verify that the "More" button has been removed.
  [[EarlGrey selectElementWithMatcher:moreButtonMatcher]
      assertWithMatcher:grey_nil()];
  // Tap on the Continue button. This scrolls the table down to the bottom.
  id<GREYMatcher> continueButtonMatcher =
      grey_accessibilityID(kSearchEngineContinueButtonIdentifier);
  [[[EarlGrey selectElementWithMatcher:continueButtonMatcher]
      assertWithMatcher:grey_notNil()] performAction:grey_tap()];
  // Verify that the "Contine" button has been removed.
  [[EarlGrey selectElementWithMatcher:continueButtonMatcher]
      assertWithMatcher:grey_nil()];

  [SearchEngineChoiceEarlGreyUI confirmSearchEngineChoiceScreen];
  [[self class] dismissDefaultBrowserAndRemainingScreens];
  [SearchEngineChoiceEarlGreyUI
      verifyDefaultSearchEngineSetting:searchEngineToSelect];
}

// Tests that the Search Engine Choice screen is displayed, that the
// primary button is correctly updated when the user scrolls down then selects a
// search engine and that it correctly sets the default search engine.
- (void)testSearchEngineChoiceScreenScrollThenSelect {
  // Skip sign-in.
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackSecondaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];
  // Check that the choice screen is shown
  [SearchEngineChoiceEarlGreyUI verifySearchEngineChoiceScreenIsDisplayed];

  // Verify that the primary button is initially the "More" button.
  id<GREYMatcher> moreButtonMatcher =
      grey_accessibilityID(kSearchEngineMoreButtonIdentifier);
  [[EarlGrey selectElementWithMatcher:moreButtonMatcher]
      assertWithMatcher:grey_allOf(grey_enabled(), grey_notNil(), nil)];

  // Tap the primary button. This scrolls the table down to the bottom.
  [[[EarlGrey selectElementWithMatcher:moreButtonMatcher]
      assertWithMatcher:grey_notNil()] performAction:grey_tap()];

  // Verify that the primary button is now the disabled "Set as Default"
  // button.
  id<GREYMatcher> primaryActionButtonMatcher =
      grey_accessibilityID(kSetAsDefaultSearchEngineIdentifier);
  [[EarlGrey selectElementWithMatcher:primaryActionButtonMatcher]
      assertWithMatcher:grey_allOf(grey_not(grey_enabled()), grey_notNil(),
                                   nil)];

  // Select a search engine.
  NSString* searchEngineToSelect = [SearchEngineChoiceEarlGreyUI
      searchEngineNameWithPrepopulatedEngine:TemplateURLPrepopulateData::bing];
  [SearchEngineChoiceEarlGreyUI
      selectSearchEngineCellWithName:searchEngineToSelect
                     scrollDirection:kGREYDirectionUp
                              amount:300];
  [SearchEngineChoiceEarlGreyUI confirmSearchEngineChoiceScreen];

  [[self class] dismissDefaultBrowserAndRemainingScreens];
  [SearchEngineChoiceEarlGreyUI
      verifyDefaultSearchEngineSetting:searchEngineToSelect];
}

// Tests completing the FRE onboarding including the Search Engine Choice screen
// for an identity requiring reauthentication.
- (void)testSearchEngineChoiceScreenWithSigninNeedsReauth {
  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
  [SigninEarlGrey addFakeIdentity:fakeIdentity];
  [SigninEarlGrey setPersistentAuthErrorForAccount:CoreAccountId::FromGaiaId(
                                                       fakeIdentity.gaiaId)];

  // Accept sign-in on the welcome screen.
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackPrimaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];

  // Accept sync.
  [self acceptSyncOrHistory];

  // Check that the choice screen is shown.
  [SearchEngineChoiceEarlGreyUI verifySearchEngineChoiceScreenIsDisplayed];

  // Select Bing.
  NSString* searchEngineToSelect = [SearchEngineChoiceEarlGreyUI
      searchEngineNameWithPrepopulatedEngine:TemplateURLPrepopulateData::bing];
  [SearchEngineChoiceEarlGreyUI
      selectSearchEngineCellWithName:searchEngineToSelect
                     scrollDirection:kGREYDirectionDown
                              amount:50];

  // Confirm choice.
  id<GREYMatcher> continueButtonMatcher =
      grey_accessibilityID(kSearchEngineContinueButtonIdentifier);
  [[[EarlGrey selectElementWithMatcher:continueButtonMatcher]
      assertWithMatcher:grey_notNil()] performAction:grey_tap()];

  [SearchEngineChoiceEarlGreyUI confirmSearchEngineChoiceScreen];

  // Verify user is signed in.
  [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
}

// Tests that the search engine screen is skipped if the enterprise policies
// are loaded after the sign-in screen is presented.
- (void)testLoadingEnterprisePoliciesAfterPresentingFRE {
  [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent:
            FRESigninIntentRegular];
  // Load enterprise policies to skip the search engine screen.
  NSString* const enterpriseSearchEngineName = @"TestEngine";
  policy_test_utils::MergePolicyWithStringValue(
      base::SysNSStringToUTF8(enterpriseSearchEngineName),
      policy::key::kDefaultSearchProviderName);
  policy_test_utils::MergePolicyWithStringValue(
      "http://www.google.com/search?q={searchTerms}",
      policy::key::kDefaultSearchProviderSearchURL);
  policy_test_utils::MergePolicy(true,
                                 policy::key::kDefaultSearchProviderEnabled);
  // Skip sign-in.
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackSecondaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];
  // Dismiss the default browser screen.
  [[self class] dismissDefaultBrowserAndRemainingScreens];
  // Open the default search engine settings menu.
  [ChromeEarlGreyUI openSettingsMenu];
  // Verify that the correct search engine is selected. The enterprise search
  // engine's name appears in the name of the selected row.
  id<GREYMatcher> settingsSearchEngineButton =
      grey_accessibilityID(kSettingsManagedSearchEngineCellId);
  [[EarlGrey selectElementWithMatcher:settingsSearchEngineButton]
      assertWithMatcher:grey_allOf(
                            grey_accessibilityValue(enterpriseSearchEngineName),
                            grey_sufficientlyVisible(), nil)];
}

// Tests kSearchEngineChoiceScreenEventsHistogram during the FRE, with the
// following scenario:
// + Skip sign-in screen in the FRE
// + Verify search engine choice screen is presented
//    Verify SearchEngineChoiceScreenEvents::kFreChoiceScreenWasDisplayed
// + Open the Learn More dialog
//    Verfiy SearchEngineChoiceScreenEvents::kFreLearnMoreWasDisplayed
// + Close the Learn More dialog
// + Choose Bing search engine
// + Validate search engine choice screen dialog
//    Verify search_engines::SearchEngineChoiceScreenEvents::kFreDefaultWasSet
- (void)testSearchEngineChoiceScreenEventsHistogram {
  NSString* const eventHistogram =
      @(search_engines::kSearchEngineChoiceScreenEventsHistogram);
  // Skip sign-in.
  chrome_test_util::GREYAssertErrorNil(
      [MetricsAppInterface expectTotalCount:0 forHistogram:eventHistogram]);
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackSecondaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];
  // Check that the choice screen is shown
  [SearchEngineChoiceEarlGreyUI verifySearchEngineChoiceScreenIsDisplayed];
  chrome_test_util::GREYAssertErrorNil(
      [MetricsAppInterface expectTotalCount:1 forHistogram:eventHistogram]);
  chrome_test_util::GREYAssertErrorNil([MetricsAppInterface
       expectCount:1
         forBucket:static_cast<int>(
                       search_engines::SearchEngineChoiceScreenEvents::
                           kFreChoiceScreenWasDisplayed)
      forHistogram:eventHistogram]);
  // Scroll down and open the Learn More dialog.
  id<GREYMatcher> learnMoreLinkMatcher = grey_allOf(
      grey_accessibilityLabel(@"Learn more"), grey_sufficientlyVisible(), nil);
  [[self
      elementInteractionWithGreyMatcher:learnMoreLinkMatcher
                   scrollViewIdentifier:kSearchEngineChoiceScrollViewIdentifier]
      performAction:grey_tap()];
  // Verify the Learn More view was presented.
  [ChromeEarlGrey waitForUIElementToAppearWithMatcher:
                      grey_accessibilityID(
                          kSearchEngineChoiceLearnMoreAccessibilityIdentifier)];
  chrome_test_util::GREYAssertErrorNil(
      [MetricsAppInterface expectTotalCount:2 forHistogram:eventHistogram]);
  chrome_test_util::GREYAssertErrorNil([MetricsAppInterface
       expectCount:1
         forBucket:static_cast<int>(
                       search_engines::SearchEngineChoiceScreenEvents::
                           kFreLearnMoreWasDisplayed)
      forHistogram:eventHistogram]);
  // Close the Learn More dialog.
  [[EarlGrey
      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
      performAction:grey_tap()];
  // Select a search engine.
  NSString* searchEngineToSelect = [SearchEngineChoiceEarlGreyUI
      searchEngineNameWithPrepopulatedEngine:TemplateURLPrepopulateData::bing];
  [SearchEngineChoiceEarlGreyUI
      selectSearchEngineCellWithName:searchEngineToSelect
                     scrollDirection:kGREYDirectionDown
                              amount:50];
  // Tap on the Continue button. This scrolls the table down to the bottom.
  id<GREYMatcher> continueButtonMatcher =
      grey_accessibilityID(kSearchEngineContinueButtonIdentifier);
  [[[EarlGrey selectElementWithMatcher:continueButtonMatcher]
      assertWithMatcher:grey_notNil()] performAction:grey_tap()];
  [SearchEngineChoiceEarlGreyUI confirmSearchEngineChoiceScreen];
  chrome_test_util::GREYAssertErrorNil(
      [MetricsAppInterface expectTotalCount:3 forHistogram:eventHistogram]);
  chrome_test_util::GREYAssertErrorNil([MetricsAppInterface
       expectCount:1
         forBucket:static_cast<int>(
                       search_engines::SearchEngineChoiceScreenEvents::
                           kFreDefaultWasSet)
      forHistogram:eventHistogram]);
  [[self class] dismissDefaultBrowserAndRemainingScreens];
}

// Tests that incognito can be forced through the FRE with search engine screen.
- (void)testIncognitoForcedByPolicy {
  // Configure the policy to force sign-in.
  [self relaunchAppWithPolicyKey:policy::key::kIncognitoModeAvailability
                  xmlPolicyValue:"<integer>2</integer>"];

  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
  GREYAssertTrue(
      [SigninEarlGrey isIdentityAdded:fakeIdentity],
      @"Identity not added by kSignInAtStartup flag, in "
      @"`relaunchAppWithPolicyKey:xmlPolicyValue:`, during the relaunch.");

  // Verify 2 steps FRE.
  [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent:
            FRESigninIntentSigninWithPolicy];
  // Accept sign-in.
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackPrimaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];
  // Accept sync.
  [self acceptSyncOrHistory];
  // Check that UMA is on.
  GREYAssertTrue(
      [FirstRunAppInterface isUMACollectionEnabled],
      @"kMetricsReportingEnabled pref was unexpectedly false by default.");
  // Check signed in.
  [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
  // Select a search engine.
  NSString* searchEngineToSelect = [SearchEngineChoiceEarlGreyUI
      searchEngineNameWithPrepopulatedEngine:TemplateURLPrepopulateData::bing];
  [SearchEngineChoiceEarlGreyUI
      selectSearchEngineCellWithName:searchEngineToSelect
                     scrollDirection:kGREYDirectionDown
                              amount:50];
  // Tap on the Continue button. This scrolls the table down to the bottom.
  id<GREYMatcher> continueButtonMatcher =
      grey_accessibilityID(kSearchEngineContinueButtonIdentifier);
  [[[EarlGrey selectElementWithMatcher:continueButtonMatcher]
      assertWithMatcher:grey_notNil()] performAction:grey_tap()];
  [SearchEngineChoiceEarlGreyUI confirmSearchEngineChoiceScreen];
}

// Tests that the Default Browser Promo is not shown in the EEA region if
// `kSkipDefaultBrowserInFirstRun` is enabled.
- (void)testNoDefaultBrowserPromoAfterSearchEngineChoiceScreen {
  // Skip sign-in.
  [[self elementInteractionWithGreyMatcher:chrome_test_util::
                                               ButtonStackSecondaryButton()
                      scrollViewIdentifier:
                          kPromoStyleScrollViewAccessibilityIdentifier]
      performAction:grey_tap()];

  // Select a search engine.
  NSString* searchEngineToSelect = [SearchEngineChoiceEarlGreyUI
      searchEngineNameWithPrepopulatedEngine:TemplateURLPrepopulateData::bing];
  [SearchEngineChoiceEarlGreyUI
      selectSearchEngineCellWithName:searchEngineToSelect
                     scrollDirection:kGREYDirectionDown
                              amount:50];

  // Tap on the Continue button. This scrolls the table down to the bottom.
  id<GREYMatcher> continueButtonMatcher =
      grey_accessibilityID(kSearchEngineContinueButtonIdentifier);
  [[[EarlGrey selectElementWithMatcher:continueButtonMatcher]
      assertWithMatcher:grey_notNil()] performAction:grey_tap()];

  // Verify that the Default Browser Promo doesn't appear.
  [self verifyDefaultBrowserNotDisplayed];
}

@end
