// Copyright 2023 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/webui/search_engine_choice/search_engine_choice_ui.h"

#include "base/check_deref.h"
#include "base/functional/bind.h"
#include "base/json/json_writer.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/regional_capabilities/regional_capabilities_service_factory.h"
#include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service.h"
#include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service_factory.h"
#include "chrome/browser/search_engine_choice/search_engine_choice_service_factory.h"
#include "chrome/browser/ui/webui/search_engine_choice/search_engine_choice_handler.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "chrome/grit/search_engine_choice_resources.h"
#include "chrome/grit/search_engine_choice_resources_map.h"
#include "chrome/grit/signin_resources.h"
#include "components/regional_capabilities/regional_capabilities_service.h"
#include "components/search_engines/search_engine_choice/search_engine_choice_service.h"
#include "components/search_engines/search_engine_choice/search_engine_choice_utils.h"
#include "components/search_engines/search_engines_switches.h"
#include "components/search_engines/template_url.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/strings/grit/components_branded_strings.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_data_source.h"
#include "ui/webui/webui_util.h"

namespace {

// LINT.IfChange
std::string GetChoiceListJSON(
    SearchEngineChoiceDialogService& search_engine_choice_dialog_service) {
  base::ListValue choice_value_list;
  const TemplateURL::TemplateURLVector choices =
      search_engine_choice_dialog_service.GetSearchEngines();

  for (const auto& choice : choices) {
    base::DictValue choice_value;

    choice_value.Set("prepopulateId", choice->prepopulate_id());
    choice_value.Set("name", choice->short_name());
    choice_value.Set(
        "iconPath",
        base::StrCat({"chrome://theme/", choice->GetBuiltinImageResourceId()}));
    choice_value.Set("url", choice->url());
    choice_value.Set("marketingSnippet", choice->GetMarketingSnippet());
    choice_value.Set("showMarketingSnippet", false);
    choice_value_list.Append(std::move(choice_value));
  }
  return base::WriteJson(choice_value_list).value_or("");
}
// LINT.ThenChange(/chrome/browser/resources/search_engine_choice/search_engine_choice.ts:SearchEngineChoice)

}  // namespace

bool SearchEngineChoiceUIConfig::IsWebUIEnabled(
    content::BrowserContext* browser_context) {
  Profile* profile = Profile::FromBrowserContext(browser_context);
  return SearchEngineChoiceDialogServiceFactory::GetForProfile(profile);
}

SearchEngineChoiceUI::SearchEngineChoiceUI(content::WebUI* web_ui)
    : ui::MojoWebUIController(web_ui, true),
      profile_(CHECK_DEREF(Profile::FromWebUI(web_ui))) {
  content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
      web_ui->GetWebContents()->GetBrowserContext(),
      chrome::kChromeUISearchEngineChoiceHost);

  regional_capabilities::RegionalCapabilitiesService*
      regional_capabilities_service = regional_capabilities::
          RegionalCapabilitiesServiceFactory::GetForProfile(&profile_.get());
  const std::optional<
      regional_capabilities::RegionalCapabilitiesService::ChoiceScreenDesign>
      choice_screen_design =
          regional_capabilities_service->GetChoiceScreenDesign();
  CHECK(choice_screen_design.has_value());
  source->AddLocalizedString("title", choice_screen_design->title_string_id);
  source->AddLocalizedString("subtitle",
                             choice_screen_design->subtitle_1_string_id);
  source->AddLocalizedString(
      "subtitleInfoLink",
      choice_screen_design->subtitle_1_learn_more_suffix_string_id);
  source->AddLocalizedString(
      "subtitleInfoLinkA11yLabel",
      choice_screen_design->subtitle_1_learn_more_a11y_string_id);
  CHECK(!choice_screen_design->subtitle_2_string_id.has_value());
  source->AddLocalizedString("submitButtonText",
                             IDS_SEARCH_ENGINE_CHOICE_BUTTON_TITLE);
  source->AddLocalizedString("infoDialogTitle",
                             IDS_SEARCH_ENGINE_CHOICE_INFO_DIALOG_TITLE);
  source->AddLocalizedString(
      "infoDialogFirstParagraph",
      IDS_SEARCH_ENGINE_CHOICE_INFO_DIALOG_BODY_FIRST_PARAGRAPH);
  source->AddLocalizedString(
      "infoDialogSecondParagraph",
      IDS_SEARCH_ENGINE_CHOICE_INFO_DIALOG_BODY_SECOND_PARAGRAPH);
  source->AddLocalizedString(
      "infoDialogThirdParagraph",
      IDS_SEARCH_ENGINE_CHOICE_INFO_DIALOG_BODY_THIRD_PARAGRAPH);
  source->AddLocalizedString("choiceListA11yLabel",
                             IDS_SEARCH_ENGINE_CHOICE_LIST_A11Y_LABEL);
  source->AddLocalizedString("infoDialogButtonText", IDS_CLOSE);
  source->AddLocalizedString("productLogoAltText",
                             IDS_SHORT_PRODUCT_LOGO_ALT_TEXT);
  source->AddLocalizedString("moreButtonText",
                             IDS_SEARCH_ENGINE_CHOICE_MORE_BUTTON);
  source->AddLocalizedString("guestCheckboxText",
                             IDS_SEARCH_ENGINE_CHOICE_GUEST_SESSION_CHECKBOX);
  source->AddResourcePath("images/left_illustration.svg",
                          IDR_SIGNIN_IMAGES_SHARED_LEFT_BANNER_SVG);
  source->AddResourcePath("images/left_illustration_dark.svg",
                          IDR_SIGNIN_IMAGES_SHARED_LEFT_BANNER_DARK_SVG);
  source->AddResourcePath("images/right_illustration.svg",
                          IDR_SIGNIN_IMAGES_SHARED_RIGHT_BANNER_SVG);
  source->AddResourcePath("images/right_illustration_dark.svg",
                          IDR_SIGNIN_IMAGES_SHARED_RIGHT_BANNER_DARK_SVG);
  source->AddResourcePath("images/product-logo.svg", IDR_PRODUCT_LOGO_SVG);
  source->AddResourcePath("tangible_sync_style_shared.css.js",
                          IDR_SIGNIN_TANGIBLE_SYNC_STYLE_SHARED_CSS_JS);
  source->AddResourcePath("signin_vars.css.js", IDR_SIGNIN_SIGNIN_VARS_CSS_JS);

  SearchEngineChoiceDialogService* search_engine_choice_dialog_service =
      SearchEngineChoiceDialogServiceFactory::GetForProfile(&profile_.get());
  source->AddString(
      "choiceList",
      GetChoiceListJSON(CHECK_DEREF(search_engine_choice_dialog_service)));

  search_engines::SearchEngineChoiceService* search_engine_choice_service =
      search_engines::SearchEngineChoiceServiceFactory::GetForProfile(
          &profile_.get());
  source->AddBoolean(
      "showGuestCheckbox",
      search_engine_choice_service->IsDsePropagationAllowedForGuest());

  const bool is_first_run_desktop_refresh_enabled =
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
      switches::IsFirstRunDesktopRefreshEnabled(
          CHECK_DEREF(regional_capabilities_service)
              .IsInSearchEngineChoiceScreenRegion());
#else
      false;
#endif

  webui::SetupWebUIDataSource(
      source, kSearchEngineChoiceResources,
      is_first_run_desktop_refresh_enabled
          ? IDR_SEARCH_ENGINE_CHOICE_SEARCH_ENGINE_CHOICE_REFRESH_HTML
          : IDR_SEARCH_ENGINE_CHOICE_SEARCH_ENGINE_CHOICE_HTML);
}

WEB_UI_CONTROLLER_TYPE_IMPL(SearchEngineChoiceUI)

SearchEngineChoiceUI::~SearchEngineChoiceUI() = default;

void SearchEngineChoiceUI::BindInterface(
    mojo::PendingReceiver<search_engine_choice::mojom::PageHandlerFactory>
        receiver) {
  page_factory_receiver_.reset();
  page_factory_receiver_.Bind(std::move(receiver));
}

void SearchEngineChoiceUI::Initialize(
    base::OnceClosure display_dialog_callback,
    base::OnceClosure on_choice_made_callback,
    SearchEngineChoiceDialogService::EntryPoint entry_point) {
  display_dialog_callback_ = std::move(display_dialog_callback);
  on_choice_made_callback_ = std::move(on_choice_made_callback);
  entry_point_ = entry_point;

  if (entry_point_ != SearchEngineChoiceDialogService::EntryPoint::kDialog) {
    // This callback should always be populated.
    // TODO(b/344899110): Cleanup once the bug root cause is found.
    CHECK(on_choice_made_callback_);
  }
}

void SearchEngineChoiceUI::HandleSearchEngineChoiceMade(
    int prepopulate_id,
    bool save_guest_mode_selection) {
  if (entry_point_ != SearchEngineChoiceDialogService::EntryPoint::kDialog) {
    // If this callback is null, then this method has already been called, which
    // is a bug. (Or the initialization was skipped, but that would point to
    // users manually entering the URL, which is not supported)
    // TODO(b/344899110): Cleanup once the bug root cause is found.
    CHECK(on_choice_made_callback_);
  }

  SearchEngineChoiceDialogService* search_engine_choice_dialog_service =
      SearchEngineChoiceDialogServiceFactory::GetForProfile(&profile_.get());
  search_engine_choice_dialog_service->NotifyChoiceMade(
      prepopulate_id, save_guest_mode_selection, entry_point_);

  // Notify that the choice was made.
  if (on_choice_made_callback_) {
    std::move(on_choice_made_callback_).Run();
  }
}

void SearchEngineChoiceUI::HandleLearnMoreLinkClicked() {
  SearchEngineChoiceDialogService* search_engine_choice_dialog_service =
      SearchEngineChoiceDialogServiceFactory::GetForProfile(&profile_.get());

  search_engine_choice_dialog_service->NotifyLearnMoreLinkClicked(entry_point_);
}

void SearchEngineChoiceUI::HandleMoreButtonClicked() {
  SearchEngineChoiceDialogService* search_engine_choice_dialog_service =
      SearchEngineChoiceDialogServiceFactory::GetForProfile(&profile_.get());

  search_engine_choice_dialog_service->NotifyMoreButtonClicked(entry_point_);
}

void SearchEngineChoiceUI::CreatePageHandler(
    mojo::PendingReceiver<search_engine_choice::mojom::PageHandler> receiver) {
  page_handler_ = std::make_unique<SearchEngineChoiceHandler>(
      std::move(receiver), std::move(display_dialog_callback_),
      base::BindOnce(&SearchEngineChoiceUI::HandleSearchEngineChoiceMade,
                     weak_ptr_factory_.GetWeakPtr()),
      base::BindRepeating(&SearchEngineChoiceUI::HandleLearnMoreLinkClicked,
                          weak_ptr_factory_.GetWeakPtr()),
      base::BindOnce(&SearchEngineChoiceUI::HandleMoreButtonClicked,
                     weak_ptr_factory_.GetWeakPtr()));
}
