// 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/search_engines/template_url_service_factory.h"

#include <string>

#include "base/check_deref.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_selections.h"
#include "chrome/browser/search_engine_choice/search_engine_choice_service_factory.h"
#include "chrome/browser/search_engines/chrome_template_url_service_client.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data_resolver_factory.h"
#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/omnibox/common/omnibox_features.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/default_search_manager.h"
#include "components/search_engines/enterprise/enterprise_search_manager.h"
#include "components/search_engines/search_engines_pref_names.h"
#include "components/search_engines/template_url_service.h"
#include "rlz/buildflags/buildflags.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/profiles/profile_helper.h"
#endif

#if BUILDFLAG(ENABLE_RLZ)
#include "components/rlz/rlz_tracker.h"  // nogncheck crbug.com/40147906
#endif

// static
TemplateURLService* TemplateURLServiceFactory::GetForProfile(Profile* profile) {
  TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("loading"),
              "TemplateURLServiceFactory::GetForProfile");

  return static_cast<TemplateURLService*>(
      GetInstance()->GetServiceForBrowserContext(profile, true));
}

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

// static
std::unique_ptr<KeyedService> TemplateURLServiceFactory::BuildInstanceFor(
    content::BrowserContext* context) {
  base::RepeatingClosure dsp_change_callback;
#if BUILDFLAG(ENABLE_RLZ)
  dsp_change_callback = base::BindRepeating(
      base::IgnoreResult(&rlz::RLZTracker::RecordProductEvent), rlz_lib::CHROME,
      rlz::RLZTracker::ChromeOmnibox(), rlz_lib::SET_TO_GOOGLE);
#endif
  Profile* profile = Profile::FromBrowserContext(context);
  return std::make_unique<TemplateURLService>(
      CHECK_DEREF(profile->GetPrefs()),
      CHECK_DEREF(
          search_engines::SearchEngineChoiceServiceFactory::GetForProfile(
              profile)),
      CHECK_DEREF(
          TemplateURLPrepopulateData::ResolverFactory::GetForProfile(profile)),
      std::make_unique<UIThreadSearchTermsData>(),
      WebDataServiceFactory::GetKeywordWebDataForProfile(
          profile, ServiceAccessType::EXPLICIT_ACCESS),
      std::unique_ptr<TemplateURLServiceClient>(
          new ChromeTemplateURLServiceClient(
              HistoryServiceFactory::GetForProfile(
                  profile, ServiceAccessType::EXPLICIT_ACCESS))),
      dsp_change_callback);
}

TemplateURLServiceFactory::TemplateURLServiceFactory()
    : ProfileKeyedServiceFactory(
          "TemplateURLServiceFactory",
          ProfileSelections::Builder()
              .WithRegular(ProfileSelection::kRedirectedToOriginal)
              // Needed for Guest sessions because they have an omnibox and
              // thus need template URLs (search providers).
              .WithGuest(ProfileSelection::kRedirectedToOriginal)
              // It's not possible for the user to search in a system profile.
              .WithSystem(ProfileSelection::kNone)
              // TODO(crbug.com/41488885): Check if this service is needed for
              // Ash Internals.
              .WithAshInternals(ProfileSelection::kRedirectedToOriginal)
              .Build()) {
  DependsOn(search_engines::SearchEngineChoiceServiceFactory::GetInstance());
  DependsOn(HistoryServiceFactory::GetInstance());
  DependsOn(WebDataServiceFactory::GetInstance());
}

TemplateURLServiceFactory::~TemplateURLServiceFactory() = default;

std::unique_ptr<KeyedService>
TemplateURLServiceFactory::BuildServiceInstanceForBrowserContext(
    content::BrowserContext* context) const {
  Profile* profile = Profile::FromBrowserContext(context);
#if BUILDFLAG(IS_CHROMEOS)
  // ChromeOS creates various unusual profiles (login, lock screen...) that do
  // not need a template URL service and cannot search.  The only non-regular
  // profile that needs a template URL is the signin profile.  The
  // signin profile sometimes can detect a "captive portal" (i.e., a network
  // connection that requires a login before it is usable).  The captive portal
  // sign-in flow creates a window with a URL bar.  The URL bar code currently
  // assumes a template URL service exists.  (This is true even though the user
  // cannot search from the captive portal sign-in window.)
  if (!ash::ProfileHelper::IsUserProfile(profile) &&
      !ash::ProfileHelper::IsSigninProfile(profile)) {
    return nullptr;
  }
#endif

  return BuildInstanceFor(profile);
}

void TemplateURLServiceFactory::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  DefaultSearchManager::RegisterProfilePrefs(registry);
  EnterpriseSearchManager::RegisterProfilePrefs(registry);
  TemplateURLService::RegisterProfilePrefs(registry);
}

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