// Copyright 2024 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/lens/lens_overlay_languages_controller.h"

#include <memory>
#include <utility>
#include <vector>

#include "base/i18n/tag_converters.h"
#include "base/json/json_reader.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/lens/core/mojom/translate.mojom-forward.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/lens/lens_overlay_url_builder.h"
#include "chrome/common/channel_info.h"
#include "google_apis/common/api_key_request_util.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "ui/base/l10n/l10n_util.h"

namespace lens {

namespace {

constexpr int kMaxDownloadBytes = 1024 * 1024;

constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotationTag =
    net::DefineNetworkTrafficAnnotation("lens_overlay_languages", R"(
        semantics {
          sender: "Lens"
          description: "A request to the translate GetSupportedLanguages "
            "endpoint for the Lens Overlay feature in Chrome."
          trigger: "The user triggered a Lens Overlay Flow by entering "
            "the experience via an entrypoint such as the Lens icon in the "
            "toolbar or Lens context menu item. This annotation corresponds "
            "to the translate GetSupportedLanguages requests sent by the Lens "
            "overlay to get language names and codes to show in the language "
            "pickers of the full page translate feature. This response is "
            "cached in the WebUI local storage and as such the request will "
            "only be made when certain conditions are met to invalidate the "
            "cache. This can include when the browser locale was changed or "
            "data is stale by more than a defined time period (e.g. a month)."
          data: "Only the browser process's locale separated into a language "
            "code and country code are used in the request. These are used to "
            "get supported languages with display names appropriate to the "
            "user's locale."
          destination: GOOGLE_OWNED_SERVICE
          internal {
            contacts {
              email: "juanmojica@google.com"
            }
            contacts {
              email: "lens-chrome@google.com"
            }
          }
          user_data {
            type: NONE
          }
          last_reviewed: "2024-10-24"
        }
        policy {
          cookies_allowed: NO
          cookies_store: ""
          setting: "This feature is only shown in menus by default and does "
            "nothing without explicit user action."
          chrome_policy {
            LensOverlaySettings {
              LensOverlaySettings: 1
            }
          }
        }
      )");
}  // namespace

LensOverlayLanguagesController::LensOverlayLanguagesController(Profile* profile)
    : profile_(profile) {}
LensOverlayLanguagesController::~LensOverlayLanguagesController() = default;

void LensOverlayLanguagesController::SendGetSupportedLanguagesRequest(
    SupportedLanguagesRetrievedCallback callback) {
  callback_ = std::move(callback);
  url_loader_ = InitializeURLLoader();
  url_loader_->DownloadToString(
      profile_->GetURLLoaderFactory().get(),
      base::BindOnce(
          &LensOverlayLanguagesController::OnGetSupportedLanguagesResponse,
          weak_ptr_factory_.GetWeakPtr()),
      kMaxDownloadBytes);
}

void LensOverlayLanguagesController::OnGetSupportedLanguagesResponse(
    std::optional<std::string> response_body) {
  if (!response_body) {
    std::move(callback_).Run(std::string(locale_.tag_string()),
                             std::vector<mojom::LanguagePtr>(),
                             std::vector<mojom::LanguagePtr>());
    return;
  }

  std::optional<base::DictValue> result_dict =
      base::JSONReader::ReadDict(*response_body, base::JSON_PARSE_RFC);
  if (!result_dict) {
    std::move(callback_).Run(std::string(locale_.tag_string()),
                             std::vector<mojom::LanguagePtr>(),
                             std::vector<mojom::LanguagePtr>());
    return;
  }

  const base::ListValue* source_language_list =
      result_dict->FindList("sourceLanguages");
  const base::ListValue* target_language_list =
      result_dict->FindList("targetLanguages");

  std::vector<lens::mojom::LanguagePtr> source_languages =
      RetrieveLanguagesFromResults(source_language_list);
  std::vector<lens::mojom::LanguagePtr> target_languages =
      RetrieveLanguagesFromResults(target_language_list);

  if (callback_) {
    std::move(callback_).Run(std::string(locale_.tag_string()),
                             std::move(source_languages),
                             std::move(target_languages));
  }
}

std::vector<lens::mojom::LanguagePtr>
LensOverlayLanguagesController::RetrieveLanguagesFromResults(
    const base::ListValue* result_list) {
  if (!result_list) {
    return std::vector<lens::mojom::LanguagePtr>();
  }

  std::vector<lens::mojom::LanguagePtr> languages_list;
  for (const base::Value& result_language : *result_list) {
    if (!result_language.is_dict()) {
      continue;
    }

    const base::DictValue& result_language_dict = result_language.GetDict();
    const std::string* language_code =
        result_language_dict.FindString("language");
    const std::string* language_name = result_language_dict.FindString("name");
    if (language_code && language_name) {
      lens::mojom::LanguagePtr language = lens::mojom::Language::New();
      language->language_code = language_code->c_str();
      language->name = language_name->c_str();
      languages_list.push_back(std::move(language));
    }
  }
  return languages_list;
}

std::unique_ptr<network::SimpleURLLoader>
LensOverlayLanguagesController::InitializeURLLoader() {
  std::unique_ptr<network::ResourceRequest> resource_request =
      std::make_unique<network::ResourceRequest>();
  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;

  locale_ = base::i18n::GetLanguageTagFromString(
                g_browser_process->GetApplicationLocale())
                .value_or(base::i18n::GetKnownLanguageTag("und"));
  std::string_view country = locale_.region_subtag();
  std::string_view language = locale_.language_subtag();
  resource_request->url = BuildTranslateLanguagesURL(country, language);

  google_apis::AddDefaultAPIKeyToRequest(*resource_request,
                                         chrome::GetChannel());
  return network::SimpleURLLoader::Create(std::move(resource_request),
                                          kTrafficAnnotationTag);
}

}  // namespace lens
