// Copyright 2012 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/sync/sync_service_factory.h"

#include <string>
#include <utility>

#include "base/check_is_test.h"
#include "base/containers/extend.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "build/build_config.h"
#include "chrome/browser/account_settings/account_setting_service_factory.h"
#include "chrome/browser/autocomplete/aim_eligibility_service_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/collaboration/collaboration_service_factory.h"
#include "chrome/browser/consent_auditor/consent_auditor_factory.h"
#include "chrome/browser/data_sharing/data_sharing_service_factory.h"
#include "chrome/browser/data_sharing/personal_collaboration_data/personal_collaboration_data_service_factory.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/gcm/gcm_profile_service_factory.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/metrics/variations/google_groups_manager_factory.h"
#include "chrome/browser/notebooks/notebooks_service_factory.h"
#include "chrome/browser/password_manager/factories/account_password_store_factory.h"
#include "chrome/browser/password_manager/factories/password_receiver_service_factory.h"
#include "chrome/browser/password_manager/factories/password_sender_service_factory.h"
#include "chrome/browser/password_manager/factories/profile_password_store_factory.h"
#include "chrome/browser/prefs/pref_service_syncable_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/reading_list/reading_list_model_factory.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/security_events/security_event_recorder_factory.h"
#include "chrome/browser/sharing/sharing_message_bridge_factory.h"
#include "chrome/browser/signin/about_signin_internals_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/supervised_user/family_link_settings_service_factory.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "chrome/browser/sync/account_bookmark_sync_service_factory.h"
#include "chrome/browser/sync/chrome_sync_client.h"
#include "chrome/browser/sync/chrome_sync_controller_builder.h"
#include "chrome/browser/sync/cross_device_theme_tracker_factory.h"
#include "chrome/browser/sync/data_type_store_service_factory.h"
#include "chrome/browser/sync/device_info_sync_service_factory.h"
#include "chrome/browser/sync/glue/extensions_activity_monitor.h"
#include "chrome/browser/sync/local_or_syncable_bookmark_sync_service_factory.h"
#include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
#include "chrome/browser/sync/session_sync_service_factory.h"
#include "chrome/browser/sync/sync_invalidations_service_factory.h"
#include "chrome/browser/sync/tab_context_sync_service_factory.h"
#include "chrome/browser/sync/user_event_service_factory.h"
#include "chrome/browser/tab_group_sync/feature_utils.h"
#include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h"
#include "chrome/browser/tab_group_sync/tab_group_trial.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/trusted_vault/trusted_vault_service_factory.h"
#include "chrome/browser/undo/bookmark_undo_service_factory.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_paths.h"
#include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/browser_sync/common_controller_builder.h"
#include "components/collaboration/public/collaboration_service.h"
#include "components/omnibox/common/omnibox_features.h"
#include "components/password_manager/core/browser/sharing/password_receiver_service.h"
#include "components/saved_tab_groups/public/features.h"
#include "components/saved_tab_groups/public/tab_group_sync_service.h"
#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
#include "components/spellcheck/browser/pref_names.h"
#include "components/sync/base/command_line_switches.h"
#include "components/sync/base/features.h"
#include "components/sync/engine/net/http_bridge.h"
#include "components/sync/service/sync_service_impl.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/variations/service/google_groups_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/storage_partition.h"
#include "extensions/buildflags/buildflags.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"

#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
#include "chrome/browser/extensions/sync/extension_sync_service.h"  // nogncheck
#include "extensions/browser/api/storage/storage_frontend.h"        // nogncheck
#include "extensions/browser/extension_system_provider.h"           // nogncheck
#include "extensions/browser/extensions_browser_client.h"           // nogncheck
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_provider_factory.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)

#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_features.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
#include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/floating_sso/floating_sso_service_factory.h"
#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h"
#include "chrome/browser/ash/printing/synced_printers_manager_factory.h"
#include "chrome/browser/sync/desk_sync_service_factory.h"
#include "chrome/browser/sync/wifi_configuration_sync_service_factory.h"
#include "chromeos/ash/experiences/arc/arc_util.h"
#endif  // BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
#include "chrome/browser/android/webapk/webapk_sync_service.h"
#include "chrome/browser/android/webapk/webapk_sync_service_factory.h"
#include "chrome/browser/ntp_customization/ntp_android_custom_background_service_factory.h"
#include "ui/base/device_form_factor.h"

// Must come after other includes, because FromJniType() uses Profile.
#include "chrome/browser/sync/android/jni_headers/SyncServiceFactory_jni.h"
#else  // BUILDFLAG(IS_ANDROID)
#include "chrome/browser/contextual_tasks/contextual_tasks_service_factory.h"
#include "chrome/browser/skills/skills_service_factory.h"
#include "chrome/browser/webauthn/passkey_model_factory.h"
#endif  // BUILDFLAG(IS_ANDROID)

namespace {

// Returns TabGroupSyncService or null if the feature is disabled.
// Tab group sync is enabled via separate feature flags on different platforms.
tab_groups::TabGroupSyncService* GetTabGroupSyncService(Profile* profile) {
  CHECK(profile);
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
    BUILDFLAG(IS_WIN)
  tab_groups::TabGroupSyncService* service =
      tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile);
  CHECK(service);
  return service;
#elif BUILDFLAG(IS_ANDROID)
  const bool enable_tab_group_sync =
      tab_groups::IsTabGroupSyncEnabled(profile->GetPrefs());
  tab_groups::TabGroupTrial::OnTabGroupSyncEnabled(enable_tab_group_sync);
  if (!enable_tab_group_sync) {
    return nullptr;
  }
  tab_groups::TabGroupSyncService* service =
      tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile);
  CHECK(service);
  return service;
#else
  return nullptr;
#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
        // BUILDFLAG(IS_WIN)
}

// Returns TemplateURLService or nullptr if the feature is disabled. Currently,
// only on Android we have a separate feature flag for template url sync, and
// it's only enabled for LFF.
TemplateURLService* GetTemplateURLService(Profile* profile) {
  CHECK(profile);
#if BUILDFLAG(IS_ANDROID)
  if (base::FeatureList::IsEnabled(syncer::kSyncSearchEnginesAndroidLFF) &&
      base::FeatureList::IsEnabled(omnibox::kOmniboxSiteSearch)) {
    return TemplateURLServiceFactory::GetForProfile(profile);
  }
  return nullptr;
#else
  return TemplateURLServiceFactory::GetForProfile(profile);
#endif  // BUILDFLAG(IS_ANDROID)
}

autofill::AddressDataManager* GetAddressDataManager(Profile* profile) {
  auto* pdm =
      autofill::PersonalDataManagerFactory::GetForBrowserContext(profile);
  return pdm ? &pdm->address_data_manager() : nullptr;
}

syncer::DataTypeController::TypeVector CreateCommonControllers(
    Profile* profile,
    syncer::SyncService* sync_service) {
  scoped_refptr<autofill::AutofillWebDataService> profile_web_data_service =
      WebDataServiceFactory::GetAutofillWebDataForProfile(
          profile, ServiceAccessType::IMPLICIT_ACCESS);
  scoped_refptr<autofill::AutofillWebDataService> account_web_data_service =
      WebDataServiceFactory::GetAutofillWebDataForAccount(
          profile, ServiceAccessType::IMPLICIT_ACCESS);

  // This class assumes that the tasks posted by the profile and account storage
  // services will execute, in order, on the same sequence.
  // This DCHECK makes that assumption explicit.
#if DCHECK_IS_ON()
  if (account_web_data_service && profile_web_data_service) {
    profile_web_data_service->GetDBTaskRunner()->PostTask(
        FROM_HERE, base::BindOnce(
                       [](scoped_refptr<base::SequencedTaskRunner> ac_tr) {
                         CHECK(ac_tr->RunsTasksInCurrentSequence());
                       },
                       account_web_data_service->GetDBTaskRunner()));
  }
#endif  // DCHECK_IS_ON()

  browser_sync::CommonControllerBuilder builder;
  builder.SetAccountSettingService(
      AccountSettingServiceFactory::GetForBrowserContext(profile));
  // A callback is needed here because `autofill::PersonalDataManagerFactory`
  // already depends on `SyncServiceFactory`.
  builder.SetAddressDataManagerGetter(
      base::BindRepeating(&GetAddressDataManager, profile));
  builder.SetAutofillWebDataService(content::GetUIThreadTaskRunner({}),
                                    profile_web_data_service,
                                    account_web_data_service);
  builder.SetBookmarkModel(BookmarkModelFactory::GetForBrowserContext(profile));
  builder.SetBookmarkSyncService(
      LocalOrSyncableBookmarkSyncServiceFactory::GetForProfile(profile),
      AccountBookmarkSyncServiceFactory::GetForProfile(profile));
  builder.SetConsentAuditor(ConsentAuditorFactory::GetForProfile(profile));
  builder.SetCollaborationService(
      collaboration::CollaborationServiceFactory::GetForProfile(profile));
#if !BUILDFLAG(IS_ANDROID)
  builder.SetAimEligibilityService(
      AimEligibilityServiceFactory::GetForProfile(profile));
  builder.SetContextualTasksService(
      contextual_tasks::ContextualTasksServiceFactory::GetForProfile(profile));
#endif
  builder.SetDataSharingService(
      data_sharing::DataSharingServiceFactory::GetForProfile(profile));
  builder.SetPersonalCollaborationDataService(
      data_sharing::personal_collaboration_data::
          PersonalCollaborationDataServiceFactory::GetForProfile(profile));
  builder.SetDeviceInfoSyncService(
      DeviceInfoSyncServiceFactory::GetForProfile(profile));
  builder.SetDualReadingListModel(
      ReadingListModelFactory::GetAsDualReadingListForBrowserContext(profile));
  builder.SetFaviconService(FaviconServiceFactory::GetForProfile(
      profile, ServiceAccessType::IMPLICIT_ACCESS));
  builder.SetGoogleGroupsManager(
      GoogleGroupsManagerFactory::GetForBrowserContext(profile));
  builder.SetHistoryService(HistoryServiceFactory::GetForProfile(
      profile, ServiceAccessType::EXPLICIT_ACCESS));
  builder.SetIdentityManager(IdentityManagerFactory::GetForProfile(profile));
  builder.SetDataTypeStoreService(
      DataTypeStoreServiceFactory::GetForProfile(profile));
#if !BUILDFLAG(IS_ANDROID)
  builder.SetPasskeyModel(PasskeyModelFactory::GetForProfile(profile));
#endif  // !BUILDFLAG(IS_ANDROID)
  builder.SetPasswordReceiverService(
      PasswordReceiverServiceFactory::GetForProfile(profile));
  builder.SetPasswordSenderService(
      PasswordSenderServiceFactory::GetForProfile(profile));
  builder.SetPasswordStore(ProfilePasswordStoreFactory::GetForProfile(
                               profile, ServiceAccessType::IMPLICIT_ACCESS),
                           AccountPasswordStoreFactory::GetForProfile(
                               profile, ServiceAccessType::IMPLICIT_ACCESS));
  builder.SetPrefService(profile->GetPrefs());
  builder.SetPrefServiceSyncable(PrefServiceSyncableFromProfile(profile));
  builder.SetTabGroupSyncService(GetTabGroupSyncService(profile));
  builder.SetTemplateURLService(GetTemplateURLService(profile));
  builder.SetSendTabToSelfSyncService(
      SendTabToSelfSyncServiceFactory::GetForProfile(profile));
  builder.SetSessionSyncService(
      SessionSyncServiceFactory::GetForProfile(profile));
  builder.SetTabContextSyncService(
      TabContextSyncServiceFactory::GetForProfile(profile));
  builder.SetSharingMessageBridge(
      SharingMessageBridgeFactory::GetForBrowserContext(profile));
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  builder.SetFamilyLinkSettingsService(
      supervised_user::FamilyLinkSettingsServiceFactory::GetForKey(
          profile->GetProfileKey()));
#endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
  builder.SetUserEventService(
      browser_sync::UserEventServiceFactory::GetForProfile(profile));
  builder.SetSkillsService(
#if BUILDFLAG(IS_ANDROID)
      nullptr
#else   // BUILDFLAG(IS_ANDROID)
      skills::SkillsServiceFactory::GetForProfile(profile)
#endif  // BUILDFLAG(IS_ANDROID)
  );
  builder.SetNotebooksService(
      notebooks::NotebooksServiceFactory::GetForProfile(profile));

  return builder.Build(/*disabled_types=*/{}, sync_service,
                       chrome::GetChannel());
}

syncer::DataTypeController::TypeVector CreateChromeControllers(
    Profile* profile,
    syncer::SyncService* sync_service) {
  ChromeSyncControllerBuilder builder;

  builder.SetDataTypeStoreService(
      DataTypeStoreServiceFactory::GetForProfile(profile));
  builder.SetSecurityEventRecorder(
      SecurityEventRecorderFactory::GetForProfile(profile));

#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  builder.SetExtensionSyncService(ExtensionSyncService::Get(profile));
  builder.SetExtensionSystemProfile(profile);
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)

#if BUILDFLAG(ENABLE_EXTENSIONS)
  builder.SetThemeService(ThemeServiceFactory::GetForProfile(profile));
  builder.SetWebAppProvider(
      web_app::AreWebAppsEnabled(profile)
          ? web_app::WebAppProvider::GetForWebApps(profile)
          : nullptr);
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)

#if BUILDFLAG(ENABLE_SPELLCHECK)
  builder.SetSpellcheckService(
      profile->GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckEnable)
          ? SpellcheckServiceFactory::GetForContext(profile)
          : nullptr);
#endif  // BUILDFLAG(ENABLE_SPELLCHECK)

#if BUILDFLAG(IS_ANDROID)
  builder.SetNtpAndroidCustomBackgroundService(
      base::FeatureList::IsEnabled(syncer::kNewTabPageCustomizationThemeSync)
          ? NtpAndroidCustomBackgroundServiceFactory::GetForProfile(profile)
          : nullptr);
  builder.SetWebApkSyncService(
      base::FeatureList::IsEnabled(syncer::kWebApkBackupAndRestoreBackend)
          ? webapk::WebApkSyncServiceFactory::GetForProfile(profile)
          : nullptr);
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_CHROMEOS)
  const bool arc_enabled =
      arc::IsArcAllowedForProfile(profile) && !arc::IsArcAppSyncFlowDisabled();

  builder.SetAppListSyncableService(
      app_list::AppListSyncableServiceFactory::GetForProfile(profile));
  builder.SetAuthorizationZonesManager(
      ash::features::IsOAuthIppEnabled()
          ? ash::printing::oauth2::AuthorizationZonesManagerFactory::
                GetForBrowserContext(profile)
          : nullptr);
  builder.SetArcPackageSyncableService(
      arc_enabled ? arc::ArcPackageSyncableService::Get(profile) : nullptr,
      arc_enabled ? profile : nullptr);
  builder.SetDeskSyncService(DeskSyncServiceFactory::GetForProfile(profile));
  builder.SetFloatingSsoService(
      ash::features::IsFloatingSsoAllowed()
          ? ash::floating_sso::FloatingSsoServiceFactory::GetForProfile(profile)
          : nullptr);
  builder.SetOsPrefServiceSyncable(PrefServiceSyncableFromProfile(profile));
  builder.SetPrefService(profile->GetPrefs());
  builder.SetSyncedPrintersManager(
      ash::SyncedPrintersManagerFactory::GetForBrowserContext(profile));
  builder.SetWifiConfigurationSyncService(
      WifiConfigurationSyncServiceFactory::ShouldRunInProfile(profile)
          ? WifiConfigurationSyncServiceFactory::GetForProfile(profile,
                                                               /*create=*/true)
          : nullptr);
#endif  // BUILDFLAG(IS_CHROMEOS)

  builder.SetCrossDeviceThemeTracker(
      CrossDeviceThemeTrackerFactory::GetForProfile(profile));

  return builder.Build(sync_service);
}

syncer::DataTypeController::TypeVector CreateControllers(
    Profile* profile,
    syncer::SyncService* sync_service) {
  syncer::DataTypeController::TypeVector controllers =
      CreateCommonControllers(profile, sync_service);
  base::Extend(controllers, CreateChromeControllers(profile, sync_service));
  return controllers;
}

std::unique_ptr<syncer::SyncClient> BuildSyncClient(Profile* profile) {
  CHECK(profile);

  return std::make_unique<browser_sync::ChromeSyncClient>(
      profile->GetBaseName(), profile->GetPrefs(),
      IdentityManagerFactory::GetForProfile(profile),
      TrustedVaultServiceFactory::GetForProfile(profile),
      SyncInvalidationsServiceFactory::GetForProfile(profile),
      DeviceInfoSyncServiceFactory::GetForProfile(profile),
      DataTypeStoreServiceFactory::GetForProfile(profile),
      supervised_user::FamilyLinkSettingsServiceFactory::GetForKey(
          profile->GetProfileKey()),
      std::make_unique<browser_sync::ExtensionsActivityMonitor>(profile));
}

std::unique_ptr<KeyedService> BuildSyncService(
    std::optional<syncer::CreateHttpPostProviderFactory>
        create_http_post_provider_factory_for_test,
    content::BrowserContext* context) {
  if (create_http_post_provider_factory_for_test.has_value()) {
    CHECK_IS_TEST();
  }

  syncer::SyncServiceImpl::InitParams init_params;

  Profile* profile = Profile::FromBrowserContext(context);
  CHECK(profile);

  // Incognito, guest, or system profiles aren't relevant for Sync, and
  // no SyncService should be created for those types of profiles.
  CHECK(profiles::IsRegularUserProfile(profile));

  init_params.sync_client = BuildSyncClient(profile);
  init_params.url_loader_factory = profile->GetDefaultStoragePartition()
                                       ->GetURLLoaderFactoryForBrowserProcess();
  init_params.create_http_post_provider_factory =
      std::move(create_http_post_provider_factory_for_test)
          .value_or(base::BindRepeating(
              [](const std::string& user_agent,
                 std::unique_ptr<network::PendingSharedURLLoaderFactory>
                     pending_url_loader_factory)
                  -> std::unique_ptr<syncer::HttpPostProviderFactory> {
                return std::make_unique<syncer::HttpBridgeFactory>(
                    user_agent, std::move(pending_url_loader_factory));
              }));
  init_params.network_connection_tracker =
      content::GetNetworkConnectionTracker();
  init_params.channel = chrome::GetChannel();
  init_params.debug_identifier = profile->GetDebugName();
  init_params.os_crypt_async = g_browser_process->os_crypt_async();

  bool local_sync_backend_enabled = false;
  // Only check the local sync backend pref on the supported platforms of
  // Windows, Mac and Linux.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
  syncer::SyncPrefs prefs(profile->GetPrefs());
  local_sync_backend_enabled = prefs.IsLocalSyncEnabled();
  base::UmaHistogramBoolean("Sync.Local.Enabled2", local_sync_backend_enabled);

  if (local_sync_backend_enabled) {
    base::FilePath local_sync_backend_folder =
        init_params.sync_client->GetLocalSyncBackendFolder();

    // If the user has not specified a folder and we can't get the default
    // roaming profile location the sync service will not be created.
    base::UmaHistogramBoolean("Sync.Local.RoamingProfileUnavailable2",
                              local_sync_backend_folder.empty());
    if (local_sync_backend_folder.empty()) {
      return nullptr;
    }
  }
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)

  if (!local_sync_backend_enabled) {
    // Always create the GCMProfileService instance such that we can listen to
    // the profile notifications and purge the GCM store when the profile is
    // being signed out.
    gcm::GCMProfileServiceFactory::GetForProfile(profile);

    AboutSigninInternalsFactory::GetForProfile(profile);
  }

  auto sync_service =
      std::make_unique<syncer::SyncServiceImpl>(std::move(init_params));
  sync_service->Initialize(CreateControllers(profile, sync_service.get()));

  // Notify the PasswordStore of complete initialisation to resolve a circular
  // dependency.
  auto profile_password_store = ProfilePasswordStoreFactory::GetForProfile(
      profile, ServiceAccessType::EXPLICIT_ACCESS);
  // PasswordStoreInterface may be null in tests.
  if (profile_password_store) {
    profile_password_store->OnSyncServiceInitialized(sync_service.get());
  }

  auto account_password_store = AccountPasswordStoreFactory::GetForProfile(
      profile, ServiceAccessType::EXPLICIT_ACCESS);

  if (account_password_store) {
    account_password_store->OnSyncServiceInitialized(sync_service.get());
  }

  // Notify PasswordReceiverService of complete initialization to resolve a
  // circular dependency.
  password_manager::PasswordReceiverService* password_receiver_service =
      PasswordReceiverServiceFactory::GetForProfile(profile);
  if (password_receiver_service) {
    password_receiver_service->OnSyncServiceInitialized(sync_service.get());
  }

  SendTabToSelfSyncServiceFactory::GetForProfile(profile)
      ->OnSyncServiceInitialized(sync_service.get());

  collaboration::CollaborationServiceFactory::GetForProfile(profile)
      ->OnSyncServiceInitialized(sync_service.get());

  // Allow sync_preferences/ components to use SyncService.
  sync_preferences::PrefServiceSyncable* pref_service =
      PrefServiceSyncableFromProfile(profile);
  pref_service->OnSyncServiceInitialized(sync_service.get());

  if (GoogleGroupsManager* groups_updater_service =
          GoogleGroupsManagerFactory::GetForBrowserContext(profile)) {
    groups_updater_service->OnSyncServiceInitialized(sync_service.get());
  }

  return sync_service;
}

}  // namespace

// static
SyncServiceFactory* SyncServiceFactory::GetInstance() {
  static base::NoDestructor<SyncServiceFactory> instance;
  return instance.get();
}

// static
syncer::SyncService* SyncServiceFactory::GetForProfile(Profile* profile) {
  if (!syncer::IsSyncAllowedByFlag()) {
    return nullptr;
  }

  return static_cast<syncer::SyncService*>(
      GetInstance()->GetServiceForBrowserContext(profile, /*create=*/true));
}

// static
syncer::SyncServiceImpl*
SyncServiceFactory::GetAsSyncServiceImplForProfileForTesting(Profile* profile) {
  return static_cast<syncer::SyncServiceImpl*>(GetForProfile(profile));
}

SyncServiceFactory::SyncServiceFactory()
    : ProfileKeyedServiceFactory(
          "SyncService",
          ProfileSelections::Builder()
              .WithRegular(ProfileSelection::kOriginalOnly)
              .WithAshInternals(ProfileSelection::kNone)
              .Build()) {
  // The SyncServiceImpl depends on various KeyedServices being around
  // when it is shut down.  Specify those dependencies here to build the proper
  // destruction order. Note that some of the dependencies are listed here but
  // actually plumbed in ChromeSyncClient, which this factory constructs.
  DependsOn(AboutSigninInternalsFactory::GetInstance());
  DependsOn(AccountSettingServiceFactory::GetInstance());
  DependsOn(AccountBookmarkSyncServiceFactory::GetInstance());
  DependsOn(AccountPasswordStoreFactory::GetInstance());
  DependsOn(AimEligibilityServiceFactory::GetInstance());
  DependsOn(BookmarkModelFactory::GetInstance());
  DependsOn(BookmarkUndoServiceFactory::GetInstance());
  DependsOn(browser_sync::UserEventServiceFactory::GetInstance());
  DependsOn(collaboration::CollaborationServiceFactory::GetInstance());
  DependsOn(ConsentAuditorFactory::GetInstance());
#if !BUILDFLAG(IS_ANDROID)
  DependsOn(contextual_tasks::ContextualTasksServiceFactory::GetInstance());
#endif  // !BUILDFLAG(IS_ANDROID)
  DependsOn(CrossDeviceThemeTrackerFactory::GetInstance());
  DependsOn(DataTypeStoreServiceFactory::GetInstance());
  DependsOn(DeviceInfoSyncServiceFactory::GetInstance());
  DependsOn(data_sharing::DataSharingServiceFactory::GetInstance());
  DependsOn(data_sharing::personal_collaboration_data::
                PersonalCollaborationDataServiceFactory::GetInstance());
  DependsOn(FaviconServiceFactory::GetInstance());
  DependsOn(gcm::GCMProfileServiceFactory::GetInstance());
  DependsOn(GoogleGroupsManagerFactory::GetInstance());
  DependsOn(HistoryServiceFactory::GetInstance());
  DependsOn(IdentityManagerFactory::GetInstance());
  DependsOn(LocalOrSyncableBookmarkSyncServiceFactory::GetInstance());
  DependsOn(notebooks::NotebooksServiceFactory::GetInstance());
#if !BUILDFLAG(IS_ANDROID)
  DependsOn(PasskeyModelFactory::GetInstance());
#endif  // !BUILDFLAG(IS_ANDROID)
  DependsOn(PasswordReceiverServiceFactory::GetInstance());
  DependsOn(PasswordSenderServiceFactory::GetInstance());
  DependsOn(ProfilePasswordStoreFactory::GetInstance());

  DependsOn(SecurityEventRecorderFactory::GetInstance());
  DependsOn(SendTabToSelfSyncServiceFactory::GetInstance());
  DependsOn(SharingMessageBridgeFactory::GetInstance());
#if !BUILDFLAG(IS_ANDROID)
  DependsOn(skills::SkillsServiceFactory::GetInstance());
#endif  // !BUILDFLAG(IS_ANDROID)
  DependsOn(SpellcheckServiceFactory::GetInstance());
  DependsOn(SyncInvalidationsServiceFactory::GetInstance());
  DependsOn(supervised_user::FamilyLinkSettingsServiceFactory::GetInstance());
  DependsOn(SessionSyncServiceFactory::GetInstance());
  DependsOn(TabContextSyncServiceFactory::GetInstance());
  DependsOn(TemplateURLServiceFactory::GetInstance());
#if !BUILDFLAG(IS_ANDROID)
  DependsOn(ThemeServiceFactory::GetInstance());
#endif  // !BUILDFLAG(IS_ANDROID)
  DependsOn(TrustedVaultServiceFactory::GetInstance());
#if BUILDFLAG(IS_ANDROID)
  DependsOn(NtpAndroidCustomBackgroundServiceFactory::GetInstance());
  if (base::FeatureList::IsEnabled(syncer::kWebApkBackupAndRestoreBackend)) {
    DependsOn(webapk::WebApkSyncServiceFactory::GetInstance());
  }
#endif  // BUILDFLAG(IS_ANDROID)
  DependsOn(WebDataServiceFactory::GetInstance());

#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  DependsOn(
      extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
  DependsOn(extensions::StorageFrontend::GetFactoryInstance());
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)

#if BUILDFLAG(ENABLE_EXTENSIONS)
  DependsOn(web_app::WebAppProviderFactory::GetInstance());
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)

#if BUILDFLAG(IS_CHROMEOS)
  DependsOn(app_list::AppListSyncableServiceFactory::GetInstance());
  DependsOn(
      ash::printing::oauth2::AuthorizationZonesManagerFactory::GetInstance());
  DependsOn(DeskSyncServiceFactory::GetInstance());
  if (ash::features::IsFloatingSsoAllowed()) {
    DependsOn(ash::floating_sso::FloatingSsoServiceFactory::GetInstance());
  }
  DependsOn(ash::SyncedPrintersManagerFactory::GetInstance());
  DependsOn(WifiConfigurationSyncServiceFactory::GetInstance());
#endif  // BUILDFLAG(IS_CHROMEOS)
}

SyncServiceFactory::~SyncServiceFactory() = default;

std::unique_ptr<KeyedService>
SyncServiceFactory::BuildServiceInstanceForBrowserContext(
    content::BrowserContext* context) const {
  return BuildSyncService(
      /*create_http_post_provider_factory_for_test=*/std::nullopt, context);
}

bool SyncServiceFactory::ServiceIsNULLWhileTesting() const {
  return true;
}

// static
bool SyncServiceFactory::HasSyncService(Profile* profile) {
  return GetInstance()->GetServiceForBrowserContext(profile, false) != nullptr;
}

// static
bool SyncServiceFactory::IsSyncAllowed(Profile* profile) {
  DCHECK(profile);

  syncer::SyncService* sync_service = GetForProfile(profile);
  return sync_service &&
         !sync_service->HasDisableReason(
             syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY);
}

// static
std::vector<const syncer::SyncService*>
SyncServiceFactory::GetAllSyncServices() {
  std::vector<Profile*> profiles =
      g_browser_process->profile_manager()->GetLoadedProfiles();
  std::vector<const syncer::SyncService*> sync_services;
  for (Profile* profile : profiles) {
    if (HasSyncService(profile)) {
      sync_services.push_back(GetForProfile(profile));
    }
  }
  return sync_services;
}

// static
BrowserContextKeyedServiceFactory::TestingFactory
SyncServiceFactory::GetDefaultFactory(
    std::optional<syncer::CreateHttpPostProviderFactory>
        create_http_post_provider_factory_for_test) {
  return base::BindRepeating(
      &BuildSyncService, std::move(create_http_post_provider_factory_for_test));
}

#if BUILDFLAG(IS_ANDROID)
static base::android::ScopedJavaLocalRef<jobject>
JNI_SyncServiceFactory_GetForProfile(JNIEnv* env, Profile* profile) {
  DCHECK(profile);

  syncer::SyncService* sync_service =
      SyncServiceFactory::GetForProfile(profile);
  if (!sync_service) {
    return base::android::ScopedJavaLocalRef<jobject>();
  }
  return sync_service->GetJavaObject();
}
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_ANDROID)
DEFINE_JNI(SyncServiceFactory)
#endif
