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

#include "chrome/browser/ui/autofill/chrome_autofill_client.h"

#include <utility>

#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/containers/to_vector.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/user_metrics.h"
#include "base/notimplemented.h"
#include "base/notreached.h"
#include "base/rand_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/account_settings/account_setting_service_factory.h"
#include "chrome/browser/actor/actor_keyed_service.h"
#include "chrome/browser/actor/actor_task.h"
#include "chrome/browser/autofill/address_normalizer_factory.h"
#include "chrome/browser/autofill/android/save_update_address_profile_prompt_mode.h"
#include "chrome/browser/autofill/at_memory/at_memory_query_service_factory.h"
#include "chrome/browser/autofill/autocomplete_history_manager_factory.h"
#include "chrome/browser/autofill/autofill_ai_model_cache_factory.h"
#include "chrome/browser/autofill/autofill_ai_model_executor_factory.h"
#include "chrome/browser/autofill/autofill_ai_personal_context_access_manager_factory.h"
#include "chrome/browser/autofill/autofill_entity_data_manager_factory.h"
#include "chrome/browser/autofill/autofill_field_classification_model_service_factory.h"
#include "chrome/browser/autofill/autofill_optimization_guide_decider_factory.h"
#include "chrome/browser/autofill/autofill_policy_service_factory.h"
#include "chrome/browser/autofill/cross_tab_copy_paste_tracker_factory.h"
#include "chrome/browser/autofill/entity_suppression_manager_factory.h"
#include "chrome/browser/autofill/one_time_token_service_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/autofill/ui/ui_util.h"
#include "chrome/browser/autofill/valuables_data_manager_factory.h"
#include "chrome/browser/autofill/wallet_pass_access_manager_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/consent_auditor/consent_auditor_factory.h"
#include "chrome/browser/critical_actions/critical_action_factory.h"
#include "chrome/browser/device_reauth/chrome_device_authenticator_factory.h"
#include "chrome/browser/glic/public/glic_enabling.h"
#include "chrome/browser/glic/public/glic_invoke_options.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "chrome/browser/glic/public/glic_keyed_service_factory.h"
#include "chrome/browser/global_features.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/metrics/profile_metrics_service_factory.h"
#include "chrome/browser/metrics/variations/google_groups_manager_factory.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/password_manager/factories/password_manager_settings_service_factory.h"
#include "chrome/browser/password_manager/password_field_classification_model_handler_factory.h"
#include "chrome/browser/personal_context/first_run/personal_context_first_run_service_factory.h"
#include "chrome/browser/personal_context/personal_context_eligibility_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/signin_promo_util.h"
#include "chrome/browser/ssl/chrome_security_state_util.h"
#include "chrome/browser/strike_database/strike_database_factory.h"
#include "chrome/browser/subscription_eligibility/subscription_eligibility_service_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/ui/autofill/address_bubbles_controller.h"
#include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h"
#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
#include "chrome/browser/ui/autofill/chrome_otp_phish_guard_delegate.h"
#include "chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h"
#include "chrome/browser/ui/autofill/payments/credit_card_scanner_controller.h"
#include "chrome/browser/ui/autofill/payments/payments_view_factory.h"
#include "chrome/browser/ui/autofill/popup_controller_common.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/hats/hats_service.h"
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/survey_config.h"
#include "chrome/browser/ui/passwords/ui_utils.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/toasts/api/toast_id.h"
#include "chrome/browser/ui/toasts/toast_controller.h"
#include "chrome/browser/ui/user_education/browser_user_education_interface.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/webui_url_constants.h"
#include "components/account_settings/account_setting_service.h"
#include "components/application_locale_storage/application_locale_storage.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/content/browser/content_identity_credential_delegate.h"
#include "components/autofill/content/browser/integrators/email_verifier/email_verifier_delegate.h"
#include "components/autofill/core/browser/actor/actor_autofill_manager.h"
#include "components/autofill/core/browser/at_memory/at_memory_enablement_utils.h"
#include "components/autofill/core/browser/at_memory/at_memory_manager.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager.h"
#include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
#include "components/autofill/core/browser/data_manager/valuables/valuables_data_manager.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_ai/entity_type.h"
#include "components/autofill/core/browser/data_model/autofill_ai/entity_type_names.h"
#include "components/autofill/core/browser/filling/filling_product.h"
#include "components/autofill/core/browser/form_import/form_data_importer.h"
#include "components/autofill/core/browser/form_predictions_tracker.h"
#include "components/autofill/core/browser/foundations/autofill_client.h"
#include "components/autofill/core/browser/foundations/autofill_manager.h"
#include "components/autofill/core/browser/foundations/browser_autofill_manager.h"
#include "components/autofill/core/browser/integrators/identity_credential/identity_credential_delegate.h"
#include "components/autofill/core/browser/integrators/one_time_tokens/otp_field_detector.h"
#include "components/autofill/core/browser/integrators/one_time_tokens/otp_metrics_tracker.h"
#include "components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide_decider.h"
#include "components/autofill/core/browser/logging/log_router.h"
#include "components/autofill/core/browser/metrics/autofill_settings_metrics.h"
#include "components/autofill/core/browser/metrics/cross_tab_copy_paste_tracker.h"
#include "components/autofill/core/browser/ml_model/field_classification_model_handler.h"
#include "components/autofill/core/browser/payments/payments_network_interface.h"
#include "components/autofill/core/browser/permissions/autofill_policy_service.h"
#include "components/autofill/core/browser/single_field_fillers/single_field_fill_router.h"
#include "components/autofill/core/browser/studies/autofill_experiments.h"
#include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h"
#include "components/autofill/core/browser/suggestions/suggestion_type.h"
#include "components/autofill/core/browser/ui/payments/card_unmask_otp_input_dialog_controller_impl.h"
#include "components/autofill/core/browser/ui/popup_open_enums.h"
#include "components/autofill/core/common/autofill_debug_features.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/compose/buildflags.h"
#include "components/critical_actions/core/browser/critical_action_service.h"
#include "components/device_reauth/device_authenticator.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/optimization_guide/content/browser/page_content_proto_provider.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include "components/password_manager/content/browser/password_form_classification_util.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_setting.h"
#include "components/password_manager/core/browser/password_manager_settings_service.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/password_requirements_service.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/personal_context/first_run/personal_context_first_run_service.h"
#include "components/prefs/pref_service.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/security_state/core/security_state.h"
#include "components/sessions/content/session_tab_helper.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/strike_database/strike_database.h"
#include "components/sync/service/sync_service.h"
#include "components/translate/core/browser/translate_manager.h"
#include "components/unified_consent/pref_names.h"
#include "components/variations/service/google_groups_manager.h"
#include "components/variations/service/variations_service.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/mojom/content_extraction/ai_page_content.mojom.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/geometry/rect.h"
#include "url/origin.h"

#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/android/preferences/autofill/settings_navigation_helper.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/autofill/android/android_sms_otp_backend_factory.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
#include "chrome/browser/signin/android/signin_bridge.h"
#include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_autofill_controller.h"
#include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_autofill_view_impl.h"
#include "chrome/browser/ui/android/autofill/autofill_ai_save_update_entity_flow_manager.h"
#include "chrome/browser/ui/android/autofill/email_verification_bottom_sheet_bridge.h"
#include "chrome/browser/ui/android/autofill/save_update_address_profile_flow_manager.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "chrome/browser/ui/autofill/autofill_message_controller_impl.h"
#include "chrome/browser/ui/autofill/autofill_snackbar_type.h"
#include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
#include "components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/infobar.h"
#include "components/messages/android/message_enums.h"
#include "components/messages/android/messages_feature.h"
#include "components/strings/grit/components_strings.h"
#else  // !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/autofill/autofill_ai/autofill_ai_import_data_controller.h"
#include "chrome/browser/ui/autofill/autofill_field_promo_controller_impl.h"
#include "chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/email_verifier/email_verification_popup_controller.h"
#include "chrome/browser/ui/autofill/email_verifier/email_verified_toast_menu_model.h"
#include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/browser_window/public/global_browser_collection.h"
#include "chrome/browser/ui/page_info/page_info_dialog.h"
#include "chrome/browser/ui/tabs/public/tab_features.h"  // nogncheck
#include "chrome/browser/ui/toasts/api/toast_id.h"
#include "chrome/browser/ui/toasts/toast_controller.h"
#include "chrome/browser/ui/views/autofill/popup/popup_view_views.h"
#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
#include "components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager.h"
#include "components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager.h"  // nogncheck

#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(ENABLE_COMPOSE)
#include "chrome/browser/compose/chrome_compose_client.h"
#include "components/compose/core/browser/compose_manager.h"
#endif

namespace autofill {

namespace {

AutoselectFirstSuggestion ShouldAutofillPopupAutoselectFirstSuggestion(
    AutofillSuggestionTriggerSource source) {
  return AutoselectFirstSuggestion(
      source == AutofillSuggestionTriggerSource::kTextFieldDidReceiveKeyDown);
}

// Returns a string representation of `saved_entities` (comma separated). Used
// to include in product data to hats surveys.
std::string GetStringRepresentatioOfSavedEntitiesTypes(
    const base::flat_set<EntityTypeName>& saved_entities) {
  return base::JoinString(
      base::ToVector(saved_entities,
                     [](EntityTypeName name) {
                       return std::string(EntityType(name).name_as_string());
                     }),
      ",");
}

#if !BUILDFLAG(IS_ANDROID)
const base::Feature& GetFeature(AutofillClient::IphFeature iph_feature) {
  switch (iph_feature) {
    case AutofillClient::IphFeature::kAutofillAi:
      return feature_engagement::kIPHAutofillAiOptInFeature;
    case AutofillClient::IphFeature::kWalletDirectOffers:
      return feature_engagement::kIPHAutofillWalletDirectOffersFeature;
  }
  NOTREACHED();
}

ui::ElementIdentifier GetElementId(AutofillClient::IphFeature iph_feature) {
  switch (iph_feature) {
    case AutofillClient::IphFeature::kAutofillAi:
      return PopupViewViews::kAutofillAiOptInIphElementId;
    case AutofillClient::IphFeature::kWalletDirectOffers:
      return PopupViewViews::kAutofillWalletDirectOffersIphElementId;
  }
  NOTREACHED();
}

#endif  // !BUILDFLAG(IS_ANDROID)

}  // namespace

// static
void ChromeAutofillClient::CreateForWebContents(
    content::WebContents* web_contents) {
  DCHECK(web_contents);
  if (!FromWebContents(web_contents)) {
    web_contents->SetUserData(
        UserDataKey(),
        base::WrapUnique(new ChromeAutofillClient(web_contents)));
  }
}

ChromeAutofillClient::~ChromeAutofillClient() {
  // NOTE: It is too late to clean up the autofill popup; that cleanup process
  // requires that the WebContents instance still be valid and it is not at
  // this point (in particular, the WebContentsImpl destructor has already
  // finished running and we are now in the base class destructor).
  if (suggestion_controller_) {
    base::debug::DumpWithoutCrashing();
    // Hide the controller to avoid a memory leak.
    suggestion_controller_->Hide(SuggestionHidingReason::kTabGone);
  }
}

ChromeAutofillClient::AtMemoryCopyPasteObserver::AtMemoryCopyPasteObserver(
    ChromeAutofillClient* client)
    : content::WebContentsObserver(client->web_contents()), client_(*client) {}

void ChromeAutofillClient::AtMemoryCopyPasteObserver::OnTextCopiedToClipboard(
    content::RenderFrameHost* render_frame_host,
    const std::u16string& copied_text) {
  CrossTabCopyPasteTracker* tracker =
      CrossTabCopyPasteTrackerFactory::GetForBrowserContext(
          client_->web_contents()->GetBrowserContext());
  if (!tracker) {
    return;
  }
  tracker->OnCopy(sessions::SessionTabHelper::IdForTab(client_->web_contents()),
                  base::FastHash(base::as_byte_span(copied_text)),
                  render_frame_host->GetPageUkmSourceId());
}

void ChromeAutofillClient::AtMemoryCopyPasteObserver::OnPaste() {
  CrossTabCopyPasteTracker* tracker =
      CrossTabCopyPasteTrackerFactory::GetForBrowserContext(
          client_->web_contents()->GetBrowserContext());
  if (!tracker) {
    return;
  }
  const SessionID current_tab_id =
      sessions::SessionTabHelper::IdForTab(client_->web_contents());
  if (tracker->OnPaste(current_tab_id, client_->web_contents()
                                           ->GetPrimaryMainFrame()
                                           ->GetPageUkmSourceId())) {
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
    client_->ShowAutofillAtMemoryPromo();
#endif
  }
}

// Observes direct user interaction events to detect hotkey paste (e.g., Ctrl+V,
// Cmd+V, Ctrl+Shift+V, Cmd+Shift+V, Option+Cmd+Shift+V). Hotkey paste needs to
// be observed separately because `WebContentsObserver::OnPaste()` is not
// guaranteed to be triggered by hotkey paste.
//
// Note: This function doesn't need to perfectly detect hotkey paste. For
// example, a false positive can happen when JS handles Ctrl+V and prevents the
// default action. Slight false positives are OK for promo triggering since the
// promo is displayed rarely anyway, and for metrics, comparing the copied value
// hash to the pasted value hash effectively prevents most false positives.
void ChromeAutofillClient::AtMemoryCopyPasteObserver::DidGetUserInteraction(
    const blink::WebInputEvent& event) {
  if constexpr (BUILDFLAG(IS_ANDROID)) {
    return;
  }

  if (event.GetType() != blink::WebInputEvent::Type::kRawKeyDown &&
      event.GetType() != blink::WebInputEvent::Type::kKeyDown) {
    return;
  }

  const auto& key_event = static_cast<const blink::WebKeyboardEvent&>(event);
  const int modifiers = key_event.GetModifiers();
#if BUILDFLAG(IS_MAC)
  constexpr int kPasteModifier = blink::WebInputEvent::kMetaKey;
#else
  constexpr int kPasteModifier = blink::WebInputEvent::kControlKey;
#endif

  const bool is_paste = (key_event.windows_key_code == ui::VKEY_V) &&
                        (modifiers & kPasteModifier);

  if (!is_paste) {
    return;
  }

  // Ignore hotkey events when no editable element is focused to reduce false
  // positives.
  if (!web_contents() || !web_contents()->IsFocusedElementEditable()) {
    return;
  }

  OnPaste();
}

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
void ChromeAutofillClient::ShowAutofillAtMemoryPromo() {
  // TODO(crbug.com/519061643) Double check if we also need to check a field
  // url here.
  if (!MayPerformAtMemoryAction(AtMemoryAction::kShowIph, *this,
                                GetLastCommittedPrimaryMainFrameURL())) {
    return;
  }
  auto* user_education_interface =
      BrowserUserEducationInterface::MaybeGetForWebContentsInTab(
          web_contents());
  if (user_education_interface) {
    user_education_interface->MaybeShowFeaturePromo(
        feature_engagement::kIPHAutofillAtMemoryFeature);
  }
}
#endif

ChromeAutofillClient::AtMemoryCopyPasteObserver&
ChromeAutofillClient::at_memory_copy_paste_observer() {
  return at_memory_copy_paste_observer_;
}

base::WeakPtr<AutofillClient> ChromeAutofillClient::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

const std::string& ChromeAutofillClient::GetAppLocale() const {
  return g_browser_process->GetFeatures()->application_locale_storage()->Get();
}

version_info::Channel ChromeAutofillClient::GetChannel() const {
  return chrome::GetChannel();
}

bool ChromeAutofillClient::IsOffTheRecord() const {
  auto* mutable_this = const_cast<ChromeAutofillClient*>(this);
  return mutable_this->web_contents()->GetBrowserContext()->IsOffTheRecord();
}

const subscription_eligibility::SubscriptionEligibilityService*
ChromeAutofillClient::GetSubscriptionEligibilityService() const {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return subscription_eligibility::SubscriptionEligibilityServiceFactory::
      GetForProfile(profile);
}

scoped_refptr<network::SharedURLLoaderFactory>
ChromeAutofillClient::GetURLLoaderFactory() {
  return web_contents()
      ->GetBrowserContext()
      ->GetDefaultStoragePartition()
      ->GetURLLoaderFactoryForBrowserProcess();
}

AutofillCrowdsourcingManager& ChromeAutofillClient::GetCrowdsourcingManager() {
  if (!crowdsourcing_manager_) {
    // Lazy initialization to avoid virtual function calls in the constructor.
    crowdsourcing_manager_ =
        std::make_unique<AutofillCrowdsourcingManager>(this, GetChannel());
  }
  return *crowdsourcing_manager_;
}

VotesUploader& ChromeAutofillClient::GetVotesUploader() {
  return votes_uploader_;
}

AutofillOptimizationGuideDecider*
ChromeAutofillClient::GetAutofillOptimizationGuideDecider() const {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return profile->ShutdownStarted()
             ? nullptr
             : AutofillOptimizationGuideDeciderFactory::GetForProfile(profile);
}

FieldClassificationModelHandler*
ChromeAutofillClient::GetAutofillFieldClassificationModelHandler() {
  if (base::FeatureList::IsEnabled(features::kAutofillModelPredictions)) {
    return AutofillFieldClassificationModelServiceFactory::GetForBrowserContext(
        web_contents()->GetBrowserContext());
  }
  return nullptr;
}

FieldClassificationModelHandler*
ChromeAutofillClient::GetPasswordManagerFieldClassificationModelHandler() {
  return PasswordFieldClassificationModelHandlerFactory::GetForBrowserContext(
      web_contents()->GetBrowserContext());
}

PersonalDataManager& ChromeAutofillClient::GetPersonalDataManager() {
  return CHECK_DEREF(PersonalDataManagerFactory::GetForBrowserContext(
      web_contents()->GetBrowserContext()));
}

ValuablesDataManager* ChromeAutofillClient::GetValuablesDataManager() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return ValuablesDataManagerFactory::GetForProfile(profile);
}

EntityDataManager* ChromeAutofillClient::GetEntityDataManager() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return AutofillEntityDataManagerFactory::GetForProfile(profile);
}

WalletPassAccessManager* ChromeAutofillClient::GetWalletPassAccessManager() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return WalletPassAccessManagerFactory::GetForProfile(profile);
}

personal_context::PersonalContextFirstRunService*
ChromeAutofillClient::GetPersonalContextFirstRunService() {
  Profile* profile = GetProfile();
  return PersonalContextFirstRunServiceFactory::GetForProfile(profile);
}

SingleFieldFillRouter& ChromeAutofillClient::GetSingleFieldFillRouter() {
  return single_field_fill_router_;
}

AutocompleteHistoryManager*
ChromeAutofillClient::GetAutocompleteHistoryManager() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return AutocompleteHistoryManagerFactory::GetForProfile(profile);
}

AutofillComposeDelegate* ChromeAutofillClient::GetComposeDelegate() {
#if BUILDFLAG(ENABLE_COMPOSE)
  auto* client = ChromeComposeClient::FromWebContents(web_contents());
  return client ? &client->GetManager() : nullptr;
#else
  return nullptr;
#endif
}

AtMemoryQueryService* ChromeAutofillClient::GetAtMemoryQueryService() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return AtMemoryQueryServiceFactory::GetForProfile(profile);
}

AtMemoryManager* ChromeAutofillClient::GetAtMemoryManager() {
  return at_memory_manager_.get();
}

personal_context::PersonalContextEligibilityState
ChromeAutofillClient::GetPersonalContextEligibilityState() const {
  Profile* profile = GetProfile();
  personal_context::PersonalContextEligibilityService* service =
      PersonalContextEligibilityServiceFactory::GetForProfile(profile);
  return service ? service->GetEligibilityState()
                 : personal_context::PersonalContextEligibilityState::
                       kDisabledNotEligible;
}

personal_context::PersonalContextEligibilityService*
ChromeAutofillClient::GetPersonalContextEligibilityService() const {
  Profile* profile = GetProfile();
  return PersonalContextEligibilityServiceFactory::GetForProfile(profile);
}

PasswordManagerDelegate* ChromeAutofillClient::GetPasswordManagerDelegate(
    const FieldGlobalId& field_id) {
  ChromePasswordManagerClient* client =
      ChromePasswordManagerClient::FromWebContents(web_contents());
  return client ? client->GetAutofillDelegate(field_id) : nullptr;
}

void ChromeAutofillClient::GetAiPageContent(GetAiPageContentCallback callback) {
  blink::mojom::AIPageContentOptionsPtr extraction_options =
      optimization_guide::DefaultAIPageContentOptions(
          /*on_critical_path =*/false);
  optimization_guide::GetAIPageContent(
      web_contents(), std::move(extraction_options),
      base::BindOnce([](optimization_guide::AIPageContentResultOrError result)
                         -> std::optional<
                             optimization_guide::proto::AnnotatedPageContent> {
        if (!result.has_value()) {
          return std::nullopt;
        }
        // For now, discard all other metadata about the request.
        return std::move(result)->proto;
      }).Then(std::move(callback)));
}

AutofillAiManager* ChromeAutofillClient::GetAutofillAiManager() {
  return autofill_ai_manager_.get();
}

AutofillAiPersonalContextAccessManager*
ChromeAutofillClient::GetAutofillAiPersonalContextAccessManager() {
  if (!base::FeatureList::IsEnabled(features::kAutofillAmbientAutofill)) {
    return nullptr;
  }
  return AutofillAiPersonalContextAccessManagerFactory::GetForProfile(
      GetProfile());
}

EntitySuppressionManager* ChromeAutofillClient::GetEntitySuppressionManager() {
  return EntitySuppressionManagerFactory::GetForProfile(GetProfile());
}

AutofillAiModelCache* ChromeAutofillClient::GetAutofillAiModelCache() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return AutofillAiModelCacheFactory::GetForProfile(profile);
}

AutofillAiModelExecutor* ChromeAutofillClient::GetAutofillAiModelExecutor() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return AutofillAiModelExecutorFactory::GetForProfile(profile);
}

consent_auditor::ConsentAuditor* ChromeAutofillClient::GetConsentAuditor() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return ConsentAuditorFactory::GetForProfile(profile);
}

optimization_guide::RemoteModelExecutor*
ChromeAutofillClient::GetRemoteModelExecutor() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  if (!profile || profile->ShutdownStarted()) {
    return nullptr;
  }
  OptimizationGuideKeyedService* service =
      OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
  return service;
}

IdentityCredentialDelegate*
ChromeAutofillClient::GetIdentityCredentialDelegate() {
  if (!(base::FeatureList::IsEnabled(::features::kFedCmDelegation) ||
        base::FeatureList::IsEnabled(::features::kFedCmAutofill))) {
    return nullptr;
  }

  return &identity_credential_delegate_;
}

PrefService* ChromeAutofillClient::GetPrefs() {
  return const_cast<PrefService*>(std::as_const(*this).GetPrefs());
}

const PrefService* ChromeAutofillClient::GetPrefs() const {
  return Profile::FromBrowserContext(web_contents()->GetBrowserContext())
      ->GetPrefs();
}

syncer::SyncService* ChromeAutofillClient::GetSyncService() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return SyncServiceFactory::GetForProfile(profile);
}

signin::IdentityManager* ChromeAutofillClient::GetIdentityManager() {
  return const_cast<signin::IdentityManager*>(
      std::as_const(*this).GetIdentityManager());
}

const signin::IdentityManager* ChromeAutofillClient::GetIdentityManager()
    const {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return IdentityManagerFactory::GetForProfile(profile->GetOriginalProfile());
}

metrics::ProfileMetricsService*
ChromeAutofillClient::GetProfileMetricsService() {
  Profile* profile = GetProfile();
  CHECK(profile);
  return ProfileMetricsServiceFactory::GetForProfile(profile);
}

const GoogleGroupsManager* ChromeAutofillClient::GetGoogleGroupsManager()
    const {
  // Always return the GoogleGroupsManager of the original profile to allow us
  // to do per-profile feature checks.
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return GoogleGroupsManagerFactory::GetForBrowserContext(
      profile->GetOriginalProfile());
}

FormDataImporter* ChromeAutofillClient::GetFormDataImporter() {
  if (!form_data_importer_) {
    Profile* profile =
        Profile::FromBrowserContext(web_contents()->GetBrowserContext());
    form_data_importer_ = std::make_unique<FormDataImporter>(
        this, HistoryServiceFactory::GetForProfile(
                  profile, ServiceAccessType::EXPLICIT_ACCESS));
  }
  return form_data_importer_.get();
}

payments::ChromePaymentsAutofillClient*
ChromeAutofillClient::GetPaymentsAutofillClient() {
  return &payments_autofill_client_;
}

strike_database::StrikeDatabase* ChromeAutofillClient::GetStrikeDatabase() {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  // No need to return a StrikeDatabase in incognito mode. It is primarily
  // used to determine whether or not to offer save of Autofill data. However,
  // we don't allow saving of Autofill data while in incognito anyway, so an
  // incognito code path should never get far enough to query StrikeDatabase.
  return StrikeDatabaseFactory::GetForProfile(profile);
}

ukm::UkmRecorder* ChromeAutofillClient::GetUkmRecorder() {
  return ukm::UkmRecorder::Get();
}

AddressNormalizer* ChromeAutofillClient::GetAddressNormalizer() {
  return AddressNormalizerFactory::GetInstance();
}

const GURL& ChromeAutofillClient::GetLastCommittedPrimaryMainFrameURL() const {
  return web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL();
}

url::Origin ChromeAutofillClient::GetLastCommittedPrimaryMainFrameOrigin()
    const {
  return web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin();
}

security_state::SecurityLevel
ChromeAutofillClient::GetSecurityLevelForUmaHistograms() {
  return chrome_security_state::GetSecurityLevel(web_contents());
}

const translate::LanguageState* ChromeAutofillClient::GetLanguageState() {
  // TODO(crbug.com/41430413): iOS vs other platforms extracts the language from
  // the top level frame vs whatever frame directly holds the form.
  auto* translate_manager =
      ChromeTranslateClient::GetManagerFromWebContents(web_contents());
  if (translate_manager) {
    return translate_manager->GetLanguageState();
  }
  return nullptr;
}

translate::TranslateDriver* ChromeAutofillClient::GetTranslateDriver() {
  // TODO(crbug.com/41430413): iOS vs other platforms extracts the language from
  // the top level frame vs whatever frame directly holds the form.
  auto* translate_client =
      ChromeTranslateClient::FromWebContents(web_contents());
  if (translate_client) {
    return translate_client->translate_driver();
  }
  return nullptr;
}

GeoIpCountryCode ChromeAutofillClient::GetVariationConfigCountryCode() const {
  variations::VariationsService* variation_service =
      g_browser_process->variations_service();
  // Retrieves the country code from variation service and converts it to upper
  // case.
  return GeoIpCountryCode(
      variation_service
          ? base::ToUpperASCII(variation_service->GetLatestCountry())
          : std::string());
}

profile_metrics::BrowserProfileType ChromeAutofillClient::GetProfileType()
    const {
  return profile_metrics::GetBrowserProfileType(GetProfile());
}

void ChromeAutofillClient::ShowAutofillSettings(
    SuggestionType suggestion_type) {
#if BUILDFLAG(IS_ANDROID)
  switch (suggestion_type) {
    case SuggestionType::kManageAddress:
      ShowAutofillProfileSettings(web_contents());
      return;
    case SuggestionType::kManageCreditCard:
    case SuggestionType::kManageIban:
      ShowAutofillCreditCardSettings(web_contents());
      return;
    case SuggestionType::kManageAutofillAi:
    case SuggestionType::kManageEnhancedAutofill:
      ShowAutofillPersonalContextSettings(
          web_contents(),
          AutofillOptionsReferrer::kPersonalContextAtmemoryNotice);
      return;
    default:
      break;
  }
#else
  BrowserWindowInterface* browser =
      GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(
          web_contents());
  if (browser) {
    switch (suggestion_type) {
      case SuggestionType::kManageAddress:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser, chrome::kContactInfoSubPage);
        return;
      case SuggestionType::kManageAutofillAi:
      case SuggestionType::kAutofillAiPrivateInferenceNotice:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser, chrome::kAutofillSubPage);
        return;
      case SuggestionType::kManageAutofillAiIdentityDocs:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser, chrome::kIdentityDocsSubPage);
        return;
      case SuggestionType::kManageAutofillAiTravel:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser, chrome::kTravelSubPage);
        return;
      case SuggestionType::kManageAutofillAiShopping:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser, chrome::kShoppingSubPage);
        return;
      case SuggestionType::kManageCreditCard:
      case SuggestionType::kManageIban:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser, chrome::kPaymentsSubPage);
        return;
      case SuggestionType::kManageLoyaltyCard:
        static constexpr std::string_view kValuableManagementUrl =
            "https://wallet.google.com/"
            "wallet?p=loyalty&utm_source=chrome&utm_medium=redirect&utm_"
            "campaign=loyalty";
        ShowSingletonTab(browser, GURL(kValuableManagementUrl));
        return;
      case SuggestionType::kManageEnhancedAutofill:
        base::UmaHistogramEnumeration(
            "Autofill.YourSavedInfoSettingsPage.VisitReferrer",
            autofill_metrics::AutofillSettingsReferrer::kFillingFlowDropdown);
        chrome::ShowSettingsSubPage(browser,
                                    chrome::kSuggestionsFromGeminiSubPage);
        return;
      default:
        NOTREACHED();
    }
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ConfirmSaveAddressProfile(
    const AutofillProfile& profile,
    const AutofillProfile* original_profile,
    SaveAddressBubbleType save_address_bubble_type,
    AddressProfileSavePromptCallback callback) {
#if BUILDFLAG(IS_ANDROID)
  save_update_address_profile_flow_manager_->OfferSave(
      profile, original_profile,
      save_address_bubble_type == SaveAddressBubbleType::kMigrateToAccount
          ? SaveUpdateAddressProfilePromptMode::kMigrateProfile
          : SaveUpdateAddressProfilePromptMode::kSaveNewProfile,
      std::move(callback));
#else
  AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
      web_contents(), profile, original_profile, save_address_bubble_type,
      !GetPersonalDataManager().address_data_manager().GetProfiles().empty(),
      std::move(callback));
#endif
}

AutofillClient::SuggestionUiSessionId
ChromeAutofillClient::ShowAutofillSuggestions(
    const PopupOpenArgs& open_args,
    base::WeakPtr<AutofillSuggestionDelegate> delegate) {
  // The Autofill Popup cannot open if it overlaps with another popup.
  // Therefore, the IPH is hidden before showing the Autofill Popup.
  HideAutofillFieldIph();

  // IPH hiding is asynchronous. Posting showing the Autofill Popup
  // guarantees the IPH will be hidden by the time the Autofill Popup will
  // attempt to open. This works because the tasks of hiding the IPH and showing
  // the Autofill Popup are posted on the same thread (UI thread).
  const FieldGlobalId expected_field_id =
      delegate ? delegate->GetQueriedFieldId() : FieldGlobalId();

  const SuggestionUiSessionId session_id =
      AutofillSuggestionController::GenerateSuggestionUiSessionId();
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(&ChromeAutofillClient::ShowAutofillSuggestionsImpl,
                     weak_ptr_factory_.GetWeakPtr(), session_id, open_args,
                     delegate, expected_field_id));
  return session_id;
}

void ChromeAutofillClient::UpdateAutofillDataListValues(
    base::span<const SelectOption> options) {
  if (suggestion_controller_) {
    suggestion_controller_->UpdateDataListValues(options);
  }
}

base::span<const Suggestion> ChromeAutofillClient::GetAutofillSuggestions()
    const {
  return suggestion_controller_ ? suggestion_controller_->GetSuggestions()
                                : base::span<const Suggestion>();
}

std::optional<AutofillClient::SuggestionUiSessionId>
ChromeAutofillClient::GetSessionIdForCurrentAutofillSuggestions() const {
  return suggestion_controller_ ? suggestion_controller_->GetUiSessionId()
                                : std::nullopt;
}

void ChromeAutofillClient::UpdateAutofillSuggestions(
    const std::vector<Suggestion>& suggestions,
    FillingProduct main_filling_product,
    AutofillSuggestionTriggerSource trigger_source,
    AutofillSuggestionsIgnoreFocusLoss ignore_focus_loss) {
  const std::optional<SuggestionUiSessionId> session_id =
      GetSessionIdForCurrentAutofillSuggestions();
  if (!session_id) {
    return;  // Update only if there is UI showing.
  }

  // When a form changes dynamically, `suggestion_controller_` may hold a
  // delegate of the wrong type, so updating the popup would call into the wrong
  // delegate. Hence, just close the existing popup (crbug.com/40143378).
  if (main_filling_product != suggestion_controller_->GetMainFillingProduct()) {
    suggestion_controller_->Hide(SuggestionHidingReason::kStaleData);
    return;
  }

  // Calling show will reuse the existing view automatically.
  suggestion_controller_->Show(
      *session_id, suggestions, trigger_source,
      ShouldAutofillPopupAutoselectFirstSuggestion(trigger_source),
      ignore_focus_loss, /*search_bar_initial_value=*/{});
}

void ChromeAutofillClient::HideSuggestions(
    SuggestionHidingReason reason,
    std::optional<FillingProduct> product) {
  if (!suggestion_controller_) {
    return;
  }

  // If a product filter is specified, only hide if it matches the active popup.
  if (product && product != suggestion_controller_->GetMainFillingProduct()) {
    return;
  }

  suggestion_controller_->Hide(reason);
}

void ChromeAutofillClient::TriggerUserPerceptionOfAutofillSurvey(
    FillingProduct filling_product,
    const std::map<std::string, std::string>& field_filling_stats_data) {
#if !BUILDFLAG(IS_ANDROID)
  CHECK(filling_product == FillingProduct::kAddress ||
        filling_product == FillingProduct::kCreditCard);
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  HatsService* hats_service =
      HatsServiceFactory::GetForProfile(profile, /*create_if_necessary=*/true);
  CHECK(hats_service);
  if (filling_product == FillingProduct::kAddress) {
    // Also add information about whether the granular filling feature is
    // available". The goal is to correlate the user's perception of autofill
    // with the feature.
    hats_service->LaunchDelayedSurveyForWebContents(
        kHatsSurveyTriggerAutofillAddressUserPerception, web_contents(),
        /*timeout_ms=*/5000, /*product_specific_bits_data=*/{},
        field_filling_stats_data);
  } else {
    hats_service->LaunchDelayedSurveyForWebContents(
        kHatsSurveyTriggerAutofillCreditCardUserPerception, web_contents(),
        /*timeout_ms=*/5000, /*product_specific_bits_data=*/
        {}, field_filling_stats_data);
  }
#endif
}

void ChromeAutofillClient::TriggerDeclinedSaveAddressReasonSurvey() {
#if !BUILDFLAG(IS_ANDROID)
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  auto* hats_service =
      HatsServiceFactory::GetForProfile(profile, /*create_if_necessary=*/true);
  CHECK(hats_service);
  hats_service->LaunchDelayedSurveyForWebContents(
      kHatsSurveyTriggerAutofillAddressUserDeclinedSave, web_contents(),
      /*timeout_ms=*/5000);
#endif
}

void ChromeAutofillClient::TriggerAutofillAiFillingJourneySurvey(
    bool suggestion_accepted,
    EntityType entity_type,
    const base::flat_set<EntityTypeName>& saved_entities,
    const FieldTypeSet& triggering_field_types) {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  auto* hats_service =
      HatsServiceFactory::GetForProfile(profile, /*create_if_necessary=*/true);
  CHECK(hats_service);

  hats_service->LaunchDelayedSurveyForWebContents(
      kHatsSurveyTriggerAutofillAiFilling, web_contents(),
      /*timeout_ms=*/5000, {{"User accepted suggestion", suggestion_accepted}},
      {{"Entity type", std::string(entity_type.name_as_string())},
       {"Triggering field types", FieldTypeSetToString(triggering_field_types)},
       {"Saved entities",
        GetStringRepresentatioOfSavedEntitiesTypes(saved_entities)}});
}

bool ChromeAutofillClient::IsTabInActorMode() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return actor_autofill_manager_ && actor_autofill_manager_->IsTabInActorMode();
}

ActorAutofillManager* ChromeAutofillClient::GetActorAutofillManager() {
  return actor_autofill_manager_.get();
}

int64_t ChromeAutofillClient::GetNavigationId() const {
  return web_contents()
             ? web_contents()->GetPrimaryMainFrame()->GetNavigationId()
             : 0;
}

bool ChromeAutofillClient::IsAutofillEnabled() const {
  if (IsAutofillProfileEnabled() || AutofillClient::GetPaymentsAutofillClient()
                                        ->IsAutofillPaymentMethodsEnabled()) {
    return true;
  }

  if (base::FeatureList::IsEnabled(
          features::kAutofillEnableAutofillSettingsEnterprisePolicy)) {
    const GURL& url = GetLastCommittedPrimaryMainFrameURL();
    return !IsAutofillTypeBlockedByPolicy(
               url, AutofillPolicyDataCategory::kIdentityDocs) ||
           !IsAutofillTypeBlockedByPolicy(
               url, AutofillPolicyDataCategory::kTravel) ||
           !IsAutofillTypeBlockedByPolicy(
               url, AutofillPolicyDataCategory::kShopping);
  }

  return false;
}

bool ChromeAutofillClient::IsAutofillProfileEnabled() const {
  if (!prefs::IsAutofillProfileEnabled(GetPrefs())) {
    return false;
  }

  if (base::FeatureList::IsEnabled(
          features::kAutofillEnableAutofillSettingsEnterprisePolicy) &&
      IsAutofillTypeBlockedByPolicy(GetLastCommittedPrimaryMainFrameURL(),
                                    AutofillPolicyDataCategory::kContactInfo)) {
    return false;
  }
  return true;
}

bool ChromeAutofillClient::IsAutofillTypeBlockedByPolicy(
    const GURL& url,
    AutofillPolicyDataCategory category) const {
  AutofillPolicyService* service =
      AutofillPolicyServiceFactory::GetForProfile(GetProfile());
  return service && service->IsAutofillTypeBlockedByPolicy(url, category);
}

bool ChromeAutofillClient::IsAutocompleteEnabled() const {
  return prefs::IsAutocompleteEnabled(GetPrefs());
}

bool ChromeAutofillClient::IsWalletPublicPassStorageEnabled() const {
  account_settings::AccountSettingService* setting_service =
      AccountSettingServiceFactory::GetForBrowserContext(GetProfile());
  return setting_service &&
         setting_service
             ->GetBoolean(account_settings::kWalletPrivacyContextualSurfacing)
             .value_or(false);
}

bool ChromeAutofillClient::IsPasswordManagerEnabled() const {
  password_manager::PasswordManagerSettingsService* settings_service =
      PasswordManagerSettingsServiceFactory::GetForProfile(GetProfile());
  return settings_service &&
         settings_service->IsSettingEnabled(
             password_manager::PasswordManagerSetting::kOfferToSavePasswords);
}

bool ChromeAutofillClient::UsesPlatformAutofill() const {
  return false;
}

bool ChromeAutofillClient::IsContextSecure() const {
  const auto security_level =
      chrome_security_state::GetSecurityLevel(web_contents());
  content::NavigationEntry* entry =
      web_contents()->GetController().GetVisibleEntry();

  // Only dangerous security states should prevent autofill.
  //
  // TODO(crbug.com/41307071): Once passive mixed content and legacy TLS are
  // less common, just use IsSslCertificateValid().
  return entry && entry->GetURL().SchemeIsCryptographic() &&
         security_level != security_state::DANGEROUS;
}

LogManager* ChromeAutofillClient::GetCurrentLogManager() {
  if (!log_manager_ && log_router_ && log_router_->HasReceivers()) {
    // TODO(crbug.com/40612524): Replace the closure with a callback to
    // the renderer that indicates if log messages should be sent from the
    // renderer.
    log_manager_ = LogManager::Create(log_router_, base::NullCallback());
  }
  return log_manager_.get();
}

autofill_metrics::FormInteractionsUkmLogger&
ChromeAutofillClient::GetFormInteractionsUkmLogger() {
  return form_interactions_ukm_logger_;
}

const AutofillAblationStudy& ChromeAutofillClient::GetAblationStudy() const {
  return ablation_study_;
}

#if BUILDFLAG(IS_ANDROID)
AutofillSnackbarControllerImpl*
ChromeAutofillClient::GetAutofillSnackbarController() {
  if (!autofill_snackbar_controller_impl_) {
    autofill_snackbar_controller_impl_ =
        std::make_unique<AutofillSnackbarControllerImpl>(web_contents());
  }

  return autofill_snackbar_controller_impl_.get();
}

void ChromeAutofillClient::ShowAutofillAiLoadingDialog() {
  GetAutofillDialogController()->ShowLoadingDialog(
      l10n_util::GetStringUTF16(IDS_AUTOFILL_AI_LOADING_DIALOG_LABEL),
      base::Seconds(1));
}

void ChromeAutofillClient::DismissAutofillAiLoadingDialog() {
  GetAutofillDialogController()->Dismiss();
}

AutofillDialogController* ChromeAutofillClient::GetAutofillDialogController() {
  if (!autofill_dialog_controller_impl_) {
    autofill_dialog_controller_impl_ =
        std::make_unique<AutofillDialogControllerImpl>(web_contents());
  }

  return autofill_dialog_controller_impl_.get();
}

AutofillMessageController*
ChromeAutofillClient::GetAutofillMessageController() {
  if (!autofill_message_controller_) {
    autofill_message_controller_ =
        std::make_unique<AutofillMessageControllerImpl>(web_contents());
  }

  return autofill_message_controller_.get();
}

void ChromeAutofillClient::SetTouchToFillAutofillControllerForTesting(
    std::unique_ptr<TouchToFillAutofillController>
        touch_to_fill_autofill_controller) {
  touch_to_fill_autofill_controller_ =
      std::move(touch_to_fill_autofill_controller);
}

bool ChromeAutofillClient::ShowAmbientAutoFillNotice(
    base::WeakPtr<TouchToFillAutofillDelegate> delegate) {
  if (!touch_to_fill_autofill_controller_) {
    return false;
  }
  return touch_to_fill_autofill_controller_->ShowPersonalContextNotice(
      std::make_unique<TouchToFillAutofillViewImpl>(web_contents()),
      std::move(delegate));
}

void ChromeAutofillClient::HideAmbientAutoFillNotice() {
  if (touch_to_fill_autofill_controller_) {
    touch_to_fill_autofill_controller_->Hide();
  }
}
#endif

std::unique_ptr<device_reauth::DeviceAuthenticator>
ChromeAutofillClient::GetDeviceAuthenticator(std::string histogram) const {
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || \
    BUILDFLAG(IS_CHROMEOS)
  device_reauth::DeviceAuthParams params(
      base::Seconds(60), device_reauth::DeviceAuthSource::kAutofill,
      std::move(histogram));

  return ChromeDeviceAuthenticatorFactory::GetForProfile(
      Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
      web_contents()->GetTopLevelNativeWindow(), params);
#else
  return nullptr;
#endif
}

bool ChromeAutofillClient::ShowAutofillFieldIphForFeature(
    const FormFieldData& field,
    IphFeature autofill_feature) {
#if !BUILDFLAG(IS_ANDROID)
  if (autofill_field_promo_controller_ &&
      autofill_field_promo_controller_->IsMaybeShowing()) {
    return true;
  }

  const base::Feature& feature = GetFeature(autofill_feature);

  // [Re]create the controller if `autofill_feature` isn't the current one.
  if (!autofill_field_promo_controller_ ||
      autofill_field_promo_controller_->GetFeaturePromo().name !=
          feature.name) {
    autofill_field_promo_controller_ =
        std::make_unique<AutofillFieldPromoControllerImpl>(
            web_contents(), feature, GetElementId(autofill_feature));
  }

  autofill_field_promo_controller_->Show(field.bounds());
  return autofill_field_promo_controller_->IsMaybeShowing();
#else
  return false;
#endif  // !BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::HideAutofillFieldIph() {
#if !BUILDFLAG(IS_ANDROID)
  if (autofill_field_promo_controller_) {
    autofill_field_promo_controller_->Hide();
  }
#endif  // !BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::NotifyIphFeatureUsed(
    AutofillClient::IphFeature feature) {
#if !BUILDFLAG(IS_ANDROID)
  // Based on the feature config, the IPH will not be shown ever again once the
  // user has used the `feature`. If the user is aware of it, then they
  // shouldn't be spammed with IPHs. The IPH code cannot know if the feature was
  // used or not unless explicitly notified.
  if (auto* interface =
          BrowserUserEducationInterface::MaybeGetForWebContentsInTab(
              web_contents())) {
    interface->NotifyFeaturePromoFeatureUsed(
        GetFeature(feature),
        FeaturePromoFeatureUsedAction::kClosePromoIfPresent);
  }
#endif  // !BUILDFLAG(IS_ANDROID)
}

ChromeAutofillClient::ChromeAutofillClient(content::WebContents* web_contents)
    : ContentAutofillClient(web_contents),
      ablation_study_(g_browser_process->local_state()),
      identity_credential_delegate_(web_contents),
      otp_field_detector_(std::make_unique<OtpFieldDetector>(this)),
      email_verifier_delegate_(std::make_unique<EmailVerifierDelegate>(this)),
      otp_phish_guard_delegate_(
          std::make_unique<ChromeOtpPhishGuardDelegate>(web_contents)) {
  // Initialize StrikeDatabase so its cache will be loaded and ready to use
  // when requested by other Autofill classes.
  GetStrikeDatabase();
  if (base::FeatureList::IsEnabled(features::kAutofillAiWithDataSchema)) {
    autofill_ai_manager_ = std::make_unique<AutofillAiManager>(
        this, StrikeDatabaseFactory::GetForProfile(Profile::FromBrowserContext(
                  web_contents->GetBrowserContext())));
  }
  if (base::FeatureList::IsEnabled(features::kAutofillAtMemory)) {
    at_memory_manager_ = std::make_unique<AtMemoryManager>(this);
  }
#if BUILDFLAG(IS_ANDROID)
  if (base::FeatureList::IsEnabled(features::kAutofillAiWithDataSchema)) {
    autofill_ai_save_update_entity_flow_manager_ =
        std::make_unique<AutofillAiSaveUpdateEntityFlowManager>(
            web_contents, GetAutofillMessageController(),
            GetAutofillDialogController(), GetAppLocale());
  }
  save_update_address_profile_flow_manager_ =
      std::make_unique<SaveUpdateAddressProfileFlowManager>(
          this, GetAutofillMessageController());
  touch_to_fill_autofill_controller_ =
      TouchToFillAutofillController::Create(this);
#endif

  if (actor::ActorKeyedService* actor_service =
          base::FeatureList::IsEnabled(features::kAutofillActorMode)
              ? actor::ActorKeyedService::Get(GetProfile())
              : nullptr) {
    // `base::Unretained(this)` is safe since
    // `actor_task_state_changed_subscription_` removes the subscription when
    // `this` is destroyed.
    actor_task_state_changed_subscription_ =
        actor_service->AddTaskStateChangedCallback(
            base::BindRepeating(&ChromeAutofillClient::OnActorTaskStateChange,
                                base::Unretained(this)));
  }

  form_predictions_tracker_ = std::make_unique<FormPredictionsTracker>(this);
  actor_autofill_manager_ = std::make_unique<ActorAutofillManager>(
      this,
      critical_actions::CriticalActionFactory::GetForProfile(GetProfile()));

#if !BUILDFLAG(IS_ANDROID)
  otp_metrics_tracker_ =
      std::make_unique<OtpMetricsTracker>(GetOneTimeTokenService());
#endif

  // Notify the EntityDataManager about the availability of device re-auth.
  // This information is injected through the client because the device
  // authenticator is tied to UI, even though the availability of device re-auth
  // is independent of it.
  if (EntityDataManager* edm =
          base::FeatureList::IsEnabled(features::kAutofillAiWalletPrivatePasses)
              ? GetEntityDataManager()
              : nullptr) {
    edm->SetReauthAvailability(SupportsDeviceReauth());
  }
}

Profile* ChromeAutofillClient::GetProfile() const {
  CHECK(web_contents());
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  CHECK(profile);
  return profile;
}

tabs::TabInterface* ChromeAutofillClient::GetTabInterface() {
  // Autofill is (currently) instantiated also in non-tab contexts - therefore
  // use the `MaybeGet` function.
  return tabs::TabInterface::MaybeGetFromContents(web_contents());
}

void ChromeAutofillClient::ShowEmailVerifiedToast(const GURL& issuer) {
#if BUILDFLAG(IS_ANDROID)
  GetAutofillMessageController()->Show(
      AutofillMessageModel::CreateForEmailVerified(
          issuer,
          base::BindOnce(&ShowAutofillProfileSettings, web_contents())));
#else
  // The toast is only supported on desktop for now, since Android uses
  // snackbars instead.
  if (ToastController* toast_controller = GetToastController()) {
    ToastParams params(ToastId::kEmailVerified);
    params.body_string_replacement_params.push_back(
        base::UTF8ToUTF16(issuer.host()));
    params.menu_model = std::make_unique<EmailVerifiedToastMenuModel>(
        GetTabInterface()->GetBrowserWindowInterface());
    toast_controller->MaybeShowToast(std::move(params));
  }
#endif
}

void ChromeAutofillClient::ShowEmailVerificationPopup(
    const gfx::RectF& element_bounds,
    const net::SchemefulSite& issuer_site,
    const std::u16string& email,
    base::OnceCallback<void(EmailVerificationPermissionUiStatus)> callback) {
#if BUILDFLAG(IS_ANDROID)
  if (!email_verification_bottom_sheet_bridge_) {
    auto* window_android = web_contents()->GetTopLevelNativeWindow();
    TabModel* tab_model =
        TabModelList::GetTabModelForWebContents(web_contents());
    if (window_android && tab_model) {
      email_verification_bottom_sheet_bridge_ =
          std::make_unique<EmailVerificationBottomSheetBridge>(window_android,
                                                               tab_model);
    }
  }
  if (!email_verification_bottom_sheet_bridge_) {
    std::move(callback).Run(EmailVerificationPermissionUiStatus::kOther);
    return;
  }
  email_verification_bottom_sheet_bridge_->RequestShowContent(
      base::UTF8ToUTF16(issuer_site.Serialize()), email, std::move(callback));
#else
  if (!email_verification_popup_controller_) {
    email_verification_popup_controller_ =
        std::make_unique<EmailVerificationPopupController>(web_contents());
  }
  const gfx::Rect client_area = web_contents()->GetContainerBounds();
  const gfx::RectF element_bounds_in_screen_space =
      element_bounds + client_area.OffsetFromOrigin();

  email_verification_popup_controller_->Show(
      element_bounds_in_screen_space, issuer_site, email, std::move(callback));
#endif
}

void ChromeAutofillClient::ShowAutofillSuggestionsImpl(
    SuggestionUiSessionId session_id,
    const PopupOpenArgs& open_args,
    base::WeakPtr<AutofillSuggestionDelegate> delegate,
    FieldGlobalId expected_field_id) {
  if (expected_field_id &&
      (!delegate || delegate->GetQueriedFieldId() != expected_field_id) &&
      base::FeatureList::IsEnabled(
          features::kAutofillCheckTriggeringFieldDoesNotChangeDuringFilling)) {
    return;
  }

  // Convert element_bounds to be in screen space.
  const gfx::Rect client_area = web_contents()->GetContainerBounds();
  const gfx::RectF element_bounds_in_screen_space =
      open_args.element_bounds + client_area.OffsetFromOrigin();

  // Deletes or reuses the old `suggestion_controller_`.
  suggestion_controller_ = AutofillSuggestionController::GetOrCreate(
      suggestion_controller_, delegate, web_contents(),
      PopupControllerCommon(
          open_args.frame_token, element_bounds_in_screen_space,
          open_args.text_direction, open_args.anchor_type,
          open_args.show_tabbed_popup,
          open_args.prefer_prev_arrow_side_on_suggestions_update),
      open_args.form_control_ax_id, open_args.trigger_source);

  suggestion_controller_->Show(
      session_id, open_args.suggestions, open_args.trigger_source,
      ShouldAutofillPopupAutoselectFirstSuggestion(open_args.trigger_source),
      AutofillSuggestionsIgnoreFocusLoss(false),
      open_args.search_bar_initial_value);

  // When testing, try to keep popup open when the reason to hide is one of:
  // - An external browser frame resize that is extraneous to our testing goals.
  // - Too many fields get focus one after another (for example, multiple
  // password fields being autofilled by default on Desktop).
  if (suggestion_controller_) {
    suggestion_controller_->SetKeepPopupOpenForTesting(
        keep_popup_open_for_testing_);
  }
}

std::unique_ptr<AutofillManager> ChromeAutofillClient::CreateManager(
    base::PassKey<ContentAutofillDriver> pass_key,
    ContentAutofillDriver& driver) {
  return std::make_unique<BrowserAutofillManager>(&driver);
}

credential_management::ContentCredentialManager*
ChromeAutofillClient::GetContentCredentialManager() {
  if (auto* chrome_password_manager_client =
          ChromePasswordManagerClient::FromWebContents(web_contents())) {
    return chrome_password_manager_client->GetContentCredentialManager();
  }
  return nullptr;
}

OtpFieldDetector* ChromeAutofillClient::GetOtpFieldDetector() {
  return otp_field_detector_.get();
}

OtpMetricsTracker* ChromeAutofillClient::GetOtpMetricsTracker() {
  return otp_metrics_tracker_.get();
}

OtpPhishGuardDelegate* ChromeAutofillClient::GetOtpPhishGuardDelegate() {
#if BUILDFLAG(IS_ANDROID)
  if (base::FeatureList::IsEnabled(
          password_manager::features::kOtpPhishGuard)) {
    return otp_phish_guard_delegate_.get();
  }
#endif  // BUILDFLAG(IS_ANDROID)
  return nullptr;
}

FormPredictionsTracker* ChromeAutofillClient::GetFormPredictionsTracker() {
  return form_predictions_tracker_.get();
}

one_time_tokens::OneTimeTokenService*
ChromeAutofillClient::GetOneTimeTokenService() const {
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  return OneTimeTokenServiceFactory::GetForProfile(profile);
}

void ChromeAutofillClient::set_test_addresses(
    std::vector<AutofillProfile> test_addresses) {
  test_addresses_ = std::move(test_addresses);
}

base::span<const AutofillProfile> ChromeAutofillClient::GetTestAddresses()
    const {
  return test_addresses_;
}

PasswordFormClassification ChromeAutofillClient::ClassifyAsPasswordForm(
    AutofillManager& manager,
    FormGlobalId form_id,
    FieldGlobalId field_id) const {
  return password_manager::ClassifyAsPasswordForm(manager, form_id, field_id);
}

optimization_guide::ModelQualityLogsUploaderService*
ChromeAutofillClient::GetMqlsUploadService() {
#if !BUILDFLAG(IS_ANDROID)
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  OptimizationGuideKeyedService* optimization_guide_keyed_service =
      OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
  if (!optimization_guide_keyed_service) {
    return nullptr;
  }
  return optimization_guide_keyed_service->GetModelQualityLogsUploaderService();
#else
  return nullptr;
#endif
}

void ChromeAutofillClient::ShowEntityImportBubble(
    EntityInstance new_entity,
    std::optional<EntityInstance> old_entity,
    bool save_is_synchronous,
    EntityImportPromptResultCallback prompt_result_callback) {
#if BUILDFLAG(IS_ANDROID)
  if (autofill_ai_save_update_entity_flow_manager_) {
    autofill_ai_save_update_entity_flow_manager_->OfferSave(
        new_entity, std::move(old_entity), std::move(prompt_result_callback));
  }
#else
  if (auto* controller = AutofillAiImportDataController::GetOrCreate(
          web_contents(), GetAppLocale())) {
    controller->ShowPrompt(std::move(new_entity), std::move(old_entity),
                           /*close_on_accept=*/save_is_synchronous,
                           std::move(prompt_result_callback));
  } else {
    std::move(prompt_result_callback)
        .Run(AutofillClient::AutofillAiBubbleResult::kUnknown, std::nullopt,
             {});
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::CloseEntityImportBubble() {
#if !BUILDFLAG(IS_ANDROID)
  AutofillAiImportDataController::Hide(CHECK_DEREF(web_contents()));
#endif  // !BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ShowAutofillAiLocalSaveNotification() {
#if BUILDFLAG(IS_ANDROID)
  if (autofill_ai_save_update_entity_flow_manager_) {
    autofill_ai_save_update_entity_flow_manager_->ShowLocalSaveNotification();
  }
#else
  if (auto* controller = AutofillAiImportDataController::GetOrCreate(
          web_contents(), GetAppLocale())) {
    controller->ShowLocalSaveNotification();
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ShowAutofillAiSaveToWalletFailureNotification() {
#if BUILDFLAG(IS_ANDROID)
  GetAutofillSnackbarController()->Show(
      AutofillSnackbarType::kAutofillAiSaveToWalletFailure, base::DoNothing());
#else
  if (ToastController* toast_controller = GetToastController()) {
    ToastParams params(ToastId::kAutofillAiSaveToWalletErrorMessage);
    toast_controller->MaybeShowToast(std::move(params));
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ShowAutofillAiFetchEntityFailureNotification() {
#if BUILDFLAG(IS_ANDROID)
  GetAutofillSnackbarController()->Show(
      AutofillSnackbarType::kAutofillAiFetchEntityFailure, base::DoNothing());
#else
  if (ToastController* toast_controller = GetToastController()) {
    ToastParams params(ToastId::kAutofillAiFetchEntityErrorMessage);
    toast_controller->MaybeShowToast(std::move(params));
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ShowAtMemoryFetchFailureNotification(
    std::optional<std::u16string> message_override) {
#if BUILDFLAG(IS_ANDROID)
  // TODO(crbug.com/540713368): Implement support on Android.
#else
  if (ToastController* toast_controller = GetToastController()) {
    ToastParams params(ToastId::kAtMemorySpiiFetchErrorMessage);
    params.body_string_override = std::move(message_override);
    toast_controller->MaybeShowToast(std::move(params));
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ShowAutofillAiPreFetchFailureNotification() {
#if BUILDFLAG(IS_ANDROID)
  GetAutofillMessageController()->Show(
      AutofillMessageModel::CreateForPersonalContextFetchingFailure());
#else
  if (ToastController* toast_controller = GetToastController()) {
    ToastParams params(ToastId::kAutofillAiPreFetchErrorMessage);
    toast_controller->MaybeShowToast(std::move(params));
  }
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::ShowAutofillAiPrivateInferenceNotice() {
#if BUILDFLAG(IS_ANDROID)
  base::OnceClosure action_callback = base::BindOnce(
      [](base::WeakPtr<AutofillClient> client) {
        if (client && client->GetPrefs()) {
          client->GetPrefs()->SetTime(
              prefs::kAutofillAiPrivateInferenceNoticeAcknowledgedTimestamp,
              base::Time::Now());
        }
        AutofillMetrics::LogAutofillAiPrivateInferenceNoticeInteraction(
            AutofillMetrics::PopupNoticeInteractions::kAcknowledged);
      },
      GetWeakPtr());
  messages::MessageWrapper::DismissCallback dismiss_callback =
      base::BindOnce([](messages::DismissReason unused) {
        AutofillMetrics::LogAutofillAiPrivateInferenceNoticeInteraction(
            AutofillMetrics::PopupNoticeInteractions::kDismissed);
      });
  base::RepeatingClosure secondary_action_callback = base::BindRepeating(
      [](base::WeakPtr<AutofillClient> client,
         content::WebContents* web_contents) {
        if (client && client->GetPrefs()) {
          client->GetPrefs()->SetTime(
              prefs::kAutofillAiPrivateInferenceNoticeAcknowledgedTimestamp,
              base::Time::Now());
        }
        AutofillMetrics::LogAutofillAiPrivateInferenceNoticeInteraction(
            AutofillMetrics::PopupNoticeInteractions::kLinkButtonClicked);
        ShowAutofillSettingsPage(web_contents);
      },
      GetWeakPtr(), web_contents());
  GetAutofillMessageController()->Show(
      AutofillMessageModel::CreateForPrivateInferenceNotice(
          std::move(action_callback), std::move(dismiss_callback),
          std::move(secondary_action_callback)));
  AutofillMetrics::LogAutofillAiPrivateInferenceNoticeInteraction(
      AutofillMetrics::PopupNoticeInteractions::kShown);
#endif  // BUILDFLAG(IS_ANDROID)
}

ToastController* ChromeAutofillClient::GetToastController() {
#if BUILDFLAG(IS_ANDROID)
  return nullptr;
#else
  tabs::TabInterface* tab_interface = GetTabInterface();
  if (!tab_interface) {
    return nullptr;
  }
  BrowserWindowInterface* window_interface =
      tab_interface->GetBrowserWindowInterface();
  return window_interface ? window_interface->GetFeatures().toast_controller()
                          : nullptr;
#endif  // BUILDFLAG(IS_ANDROID)
}

void ChromeAutofillClient::OnActorTaskStateChange(actor::ActorTask& task) {
  // TODO(crbug.com/551883788): Move this logic to ActorAutofillManager.
  if (!actor_autofill_manager_) {
    return;
  }
  const actor::TaskId task_id = task.id();
  const actor::ActorTask::State state = task.GetState();

  std::optional<ActorAutofillManager::ActorTaskInfo> active_task =
      actor_autofill_manager_->active_actor_task();

  if (active_task && active_task->task_id != task_id) {
    // The update is for an actor that isn't working on the current tab.
    return;
  }

  // The actor task on this tab has finished.
  // TODO(crbug.com/472336281): The state changes leading to the task
  // completion should be issued before the `ActorTask` gets removed.
  if (actor::ActorTask::IsCompletedState(state)) {
    actor_autofill_manager_->set_active_actor_task(std::nullopt);
    return;
  }

  const tabs::TabInterface* tab_interface = GetTabInterface();
  if (tab_interface && !task.HasTab(tab_interface->GetHandle())) {
    // The status update is for an actor that isn't interacting with this tab.
    // The value of `is_actor_mode_` shouldn't be updated.
    return;
  }

  // If the task was just created, known forms should be reparsed to ensure that
  // actor specific behaviors are in place.
  if (!active_task.has_value()) {
    for (AutofillDriver* driver :
         GetAutofillDriverFactory().GetExistingDrivers()) {
      driver->GetAutofillManager().ReparseKnownForms();
    }
  }

  // TODO(crbug.com/469428128): Evaluate whether
  // `actor::ActorTask::State::kCreated` state should enable the actor mode.
  actor_autofill_manager_->set_active_actor_task(
      ActorAutofillManager::ActorTaskInfo{
          .conversation_id = task.source_info().id.value_or(""),
          .task_id = task_id,
      });
}

void ChromeAutofillClient::OpenGeminiInSidebar(const std::u16string& prompt) {
  Profile* profile = GetProfile();
  if (!profile || !glic::GlicEnabling::IsEnabledForProfile(profile)) {
    return;
  }
  glic::GlicKeyedService* glic_keyed_service =
      glic::GlicKeyedServiceFactory::GetGlicKeyedService(profile);
  if (!glic_keyed_service) {
    return;
  }
  tabs::TabInterface* tab = GetTabInterface();
  if (!tab) {
    return;
  }
  glic::Target target(*tab);
  glic::GlicInvokeOptions options(std::move(target),
                                  glic::mojom::InvocationSource::kAutofill);
  options.prompts.push_back(base::UTF16ToUTF8(prompt));
  glic_keyed_service->Invoke(std::move(options));
}

bool ChromeAutofillClient::IsGlicEnabled() const {
  Profile* profile = GetProfile();
  return profile && glic::GlicEnabling::IsEnabledForProfile(profile);
}

}  // namespace autofill
