// Copyright 2025 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/test/scoped_feature_list.h"
#import "components/signin/internal/identity_manager/account_capabilities_constants.h"
#import "ios/chrome/browser/app_bar/ui/app_bar_constants.h"
#import "ios/chrome/browser/authentication/test/signin_earl_grey.h"
#import "ios/chrome/browser/authentication/test/signin_earl_grey_app_interface.h"
#import "ios/chrome/browser/authentication/test/signin_earl_grey_ui_test_util.h"
#import "ios/chrome/browser/intelligence/bwg/utils/gemini_constants.h"
#import "ios/chrome/browser/intelligence/features/features.h"
#import "ios/chrome/browser/intelligence/page_action_menu/utils/ai_hub_constants.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/browser/toolbar/ui/toolbar_constants.h"
#import "ios/chrome/common/ui/button_stack/button_stack_constants.h"
#import "ios/chrome/grit/ios_strings.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 "net/test/embedded_test_server/embedded_test_server.h"
#import "ui/base/l10n/l10n_util.h"

namespace {

// Matcher for the primary button in the promo view.
id<GREYMatcher> PromoPrimaryButton() {
  return grey_allOf(
      grey_accessibilityID(kButtonStackPrimaryActionAccessibilityIdentifier),
      grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
}

// Matcher for the secondary button in the promo view.
id<GREYMatcher> PromoSecondaryButton() {
  return grey_allOf(
      grey_accessibilityID(kButtonStackSecondaryActionAccessibilityIdentifier),
      grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
}

// Matcher for the primary button in the consent view.
id<GREYMatcher> ConsentPrimaryButton() {
  return grey_allOf(
      grey_accessibilityID(kButtonStackPrimaryActionAccessibilityIdentifier),
      grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
}

// Matcher for the secondary button in the consent view.
id<GREYMatcher> ConsentSecondaryButton() {
  return grey_allOf(
      grey_accessibilityID(kButtonStackSecondaryActionAccessibilityIdentifier),
      grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
}

// Matcher for the Gemini button.
id<GREYMatcher> GeminiButton() {
  if ([ChromeEarlGrey isChromeNextEnabled]) {
    if ([ChromeEarlGrey isIPadIdiom] && ![ChromeEarlGrey isCompactWidth]) {
      return grey_allOf(grey_accessibilityID(kToolbarAssistantButtonIdentifier),
                        grey_accessibilityTrait(UIAccessibilityTraitButton),
                        nil);
    }
    return grey_allOf(grey_accessibilityID(kAppBarAssistantButtonId),
                      grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
  }
  return grey_allOf(
      grey_accessibilityID(kAIHubAskGeminiButtonAccessibilityIdentifier),
      grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
}

}  // namespace

// Test suite for BWG UI.
@interface GeminiEGTest : ChromeTestCase
@end

@implementation GeminiEGTest

- (void)setUp {
  [super setUp];

  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];

  [SigninEarlGreyAppInterface addFakeIdentity:fakeIdentity
                             withCapabilities:@{
                               @(kCanUseModelExecutionFeaturesName) : @YES,
                               @(kCanUseGeminiInChromeCapabilityName) : @YES
                             }];

  [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
  [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
  [ChromeEarlGrey setIntegerValue:0 forUserPref:prefs::kGeminiEnabledByPolicy];
  [ChromeEarlGrey setBoolValue:NO
                   forUserPref:prefs::kAIHubEligibilityTriggered];
  [ChromeEarlGrey setBoolValue:NO forUserPref:prefs::kIOSBwgConsent];

  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
  [ChromeEarlGrey loadURL:self.testServer->GetURL("/echo")];
  [ChromeEarlGrey waitForWebStateContainingText:"Echo"];
}

- (AppLaunchConfiguration)appConfigurationForTestCase {
  AppLaunchConfiguration config = [super appConfigurationForTestCase];
  config.features_enabled.push_back(kPageActionMenu);

  if ([self isRunningTest:@selector(testAIHubNewBadgeAccessibility)]) {
    config.iph_feature_enabled = "IPH_iOSAIHubNewBadge";
    config.relaunch_policy = ForceRelaunchByKilling;
  }

  return config;
}

// Tests that when the promo is declined, the Gemini floaty is not presented.
- (void)testDeclinePromo {
  [self invokeGeminiEntryPoint];

  // Check that the promo buttons are visible.
  [[EarlGrey selectElementWithMatcher:PromoPrimaryButton()]
      assertWithMatcher:grey_sufficientlyVisible()];

  // Tap the secondary button to decline the promo.
  [[EarlGrey selectElementWithMatcher:PromoSecondaryButton()]
      performAction:grey_tap()];

  // Verify the FRE is dismissed.
  [ChromeEarlGrey
      waitForNotSufficientlyVisibleElementWithMatcher:PromoPrimaryButton()];

  // Verify consent was not granted.
  GREYAssertFalse([ChromeEarlGrey userBooleanPref:prefs::kIOSBwgConsent],
                  @"Consent should be false.");
}

// Tests that when the promo is accepted but consent is declined, the Gemini
// floaty is not presented.
- (void)testAcceptPromoDeclineConsent {
  [self invokeGeminiEntryPoint];

  // Tap the primary button to advance to the consent screen.
  [[EarlGrey selectElementWithMatcher:PromoPrimaryButton()]
      performAction:grey_tap()];

  // Wait for the consent screen to appear.
  [ChromeEarlGrey
      waitForSufficientlyVisibleElementWithMatcher:
          grey_accessibilityID(kGeminiFootNoteTextViewAccessibilityIdentifier)];

  // Check that the consent buttons are visible.
  [[EarlGrey selectElementWithMatcher:ConsentPrimaryButton()]
      assertWithMatcher:grey_sufficientlyVisible()];

  // Tap the secondary button to decline the consent.
  [[EarlGrey selectElementWithMatcher:ConsentSecondaryButton()]
      performAction:grey_tap()];

  // Verify the FRE is dismissed.
  [ChromeEarlGrey
      waitForNotSufficientlyVisibleElementWithMatcher:
          grey_accessibilityID(kGeminiFootNoteTextViewAccessibilityIdentifier)];

  // Verify consent was not granted.
  GREYAssertFalse([ChromeEarlGrey userBooleanPref:prefs::kIOSBwgConsent],
                  @"Consent should be false.");
}

// Tests that when the promo and consent are both accepted, the Gemini floaty is
// presented.
- (void)testAcceptPromoAndConsent {
  [self invokeGeminiEntryPoint];

  // Tap the primary button to advance to the consent screen.
  [[EarlGrey selectElementWithMatcher:PromoPrimaryButton()]
      performAction:grey_tap()];

  // Wait for the consent screen to appear.
  [ChromeEarlGrey
      waitForSufficientlyVisibleElementWithMatcher:
          grey_accessibilityID(kGeminiFootNoteTextViewAccessibilityIdentifier)];

  // Tap the primary button to accept the consent.
  [[EarlGrey selectElementWithMatcher:ConsentPrimaryButton()]
      performAction:grey_tap()];

  // Verify the FRE is dismissed and the flow continues.
  [ChromeEarlGrey
      waitForNotSufficientlyVisibleElementWithMatcher:
          grey_accessibilityID(kGeminiFootNoteTextViewAccessibilityIdentifier)];

  // Verify consent was granted (which triggers the floaty).
  GREYAssertTrue([ChromeEarlGrey userBooleanPref:prefs::kIOSBwgConsent],
                 @"Consent should be true.");
}

// Tests that the AI Hub entry point conveys the "New" context to accessibility.
- (void)testAIHubNewBadgeAccessibility {
  if ([ChromeEarlGrey isChromeNextEnabled]) {
    EARL_GREY_TEST_DISABLED(@"No 'new' label with Next");
  }
  NSString* baseLabel = l10n_util::GetNSString(
      IDS_IOS_BWG_PAGE_ACTION_MENU_ENTRY_POINT_ACCESSIBILITY_LABEL);
  NSString* expectedLabel =
      [NSString stringWithFormat:@"%@, %@", baseLabel,
                                 l10n_util::GetNSString(
                                     IDS_IOS_NEW_FEATURE_ACCESSIBILITY_HINT)];

  id<GREYMatcher> entrypointMatcher = grey_allOf(
      grey_accessibilityLabel(expectedLabel), grey_sufficientlyVisible(), nil);

  [[EarlGrey selectElementWithMatcher:entrypointMatcher]
      assertWithMatcher:grey_sufficientlyVisible()];
}

#pragma mark - Helpers

- (void)invokeGeminiEntryPoint {
  if ([ChromeEarlGrey isChromeNextEnabled]) {
    // With ChromeNext, the entry point is directly the Gemini button in the
    // AppBar.
    [[EarlGrey selectElementWithMatcher:GeminiButton()]
        performAction:grey_tap()];
  } else {
    id<GREYMatcher> entrypointMatcher = grey_allOf(
        grey_accessibilityID(kAIHubEntrypointAccessibilityIdentifier),
        grey_sufficientlyVisible(), nil);

    [[EarlGrey selectElementWithMatcher:entrypointMatcher]
        performAction:grey_tap()];

    // Tap the Gemini button.
    [[EarlGrey selectElementWithMatcher:GeminiButton()]
        performAction:grey_tap()];
  }
}

@end
