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

#include "components/page_image_service/image_service_impl.h"

#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "components/omnibox/browser/autocomplete_scheme_classifier.h"
#include "components/omnibox/browser/remote_suggestions_service.h"
#include "components/omnibox/browser/search_suggestion_parser.h"
#include "components/optimization_guide/core/optimization_guide_decider.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/proto/common_types.pb.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "components/optimization_guide/proto/salient_image_metadata.pb.h"
#include "components/page_image_service/features.h"
#include "components/page_image_service/image_service_consent_helper.h"
#include "components/page_image_service/metrics_util.h"
#include "components/search_engines/search_engine_type.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_service.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_response_head.mojom.h"

namespace page_image_service {

namespace {

// Fulfills all `callbacks` with `result`.
void FulfillAllCallbacks(std::vector<ImageService::ResultCallback> callbacks,
                         const GURL& result) {
  for (auto& callback : callbacks) {
    std::move(callback).Run(result);
  }
}

}  // namespace

// A one-time use object that uses Suggest to get an image URL corresponding
// to `search_query` and `entity_id`. This is a hacky temporary implementation,
// ideally this should be replaced by persisted Suggest-provided entities.
// TODO(tommycli): Move this to its own separate file with unit tests.
class ImageServiceImpl::SuggestEntityImageURLFetcher {
 public:
  SuggestEntityImageURLFetcher(
      const AutocompleteSchemeClassifier& autocomplete_scheme_classifier,
      mojom::ClientId client_id,
      const std::u16string& search_query,
      const std::string& entity_id)
      : autocomplete_scheme_classifier_(autocomplete_scheme_classifier),
        client_id_(client_id),
        search_query_(base::i18n::ToLower(search_query)),
        entity_id_(entity_id) {}
  SuggestEntityImageURLFetcher(const SuggestEntityImageURLFetcher&) = delete;

  // `callback` is called with the result.
  void Start(const TemplateURL* template_url,
             const SearchTermsData& search_terms_data,
             RemoteSuggestionsService* remote_suggestions_service,
             base::OnceCallback<void(const GURL&)> callback) {
    CHECK(template_url);
    CHECK(remote_suggestions_service);
    CHECK(!callback_);
    callback_ = std::move(callback);

    TemplateURLRef::SearchTermsArgs search_terms_args;
    search_terms_args.page_classification =
        metrics::OmniboxEventProto::JOURNEYS;
    search_terms_args.search_terms = search_query_;

    // ImageServiceFactory does not create a service instance for OTR profiles.
    loader_ = remote_suggestions_service->StartSuggestionsRequest(
        RemoteRequestType::kImages, /*is_off_the_record=*/false, template_url,
        search_terms_args, search_terms_data,
        base::BindOnce(&SuggestEntityImageURLFetcher::OnURLLoadComplete,
                       weak_factory_.GetWeakPtr()));
  }

 private:
  void OnURLLoadComplete(const network::SimpleURLLoader* source,
                         const int response_code,
                         std::unique_ptr<std::string> response_body) {
    DCHECK_EQ(loader_.get(), source);
    if (response_code != 200) {
      UmaHistogramEnumerationForClient(kBackendSuggestResultHistogramName,
                                       PageImageServiceResult::kResponseMissing,
                                       client_id_);
      return std::move(callback_).Run(GURL());
    }

    std::string response_json = SearchSuggestionParser::ExtractJsonData(
        source, std::move(response_body));
    if (response_json.empty()) {
      UmaHistogramEnumerationForClient(
          kBackendSuggestResultHistogramName,
          PageImageServiceResult::kResponseMalformed, client_id_);
      return std::move(callback_).Run(GURL());
    }

    auto response_data =
        SearchSuggestionParser::DeserializeJsonData(response_json);
    if (!response_data) {
      UmaHistogramEnumerationForClient(
          kBackendSuggestResultHistogramName,
          PageImageServiceResult::kResponseMalformed, client_id_);
      return std::move(callback_).Run(GURL());
    }

    AutocompleteInput input(search_query_, metrics::OmniboxEventProto::JOURNEYS,
                            *autocomplete_scheme_classifier_);
    SearchSuggestionParser::Results results;
    if (!SearchSuggestionParser::ParseSuggestResults(
            *response_data, input, *autocomplete_scheme_classifier_,
            /*default_result_relevance=*/100,
            /*is_keyword_result=*/false, &results)) {
      UmaHistogramEnumerationForClient(
          kBackendSuggestResultHistogramName,
          PageImageServiceResult::kResponseMalformed, client_id_);
      return std::move(callback_).Run(GURL());
    }

    for (const auto& result : results.suggest_results) {
      // TODO(tommycli): `entity_id_` is not used yet, because it's always
      // empty right now.
      GURL url(result.entity_info().image_url());
      if (url.is_valid() &&
          base::i18n::ToLower(result.match_contents()) == search_query_) {
        UmaHistogramEnumerationForClient(kBackendSuggestResultHistogramName,
                                         PageImageServiceResult::kSuccess,
                                         client_id_);
        return std::move(callback_).Run(std::move(url));
      }
    }

    // If we didn't find any matching images, still notify the caller.
    if (!callback_.is_null()) {
      UmaHistogramEnumerationForClient(kBackendSuggestResultHistogramName,
                                       PageImageServiceResult::kNoImage,
                                       client_id_);
      std::move(callback_).Run(GURL());
    }
  }

  // Embedder-specific logic on how to classify schemes.
  const raw_ref<const AutocompleteSchemeClassifier>
      autocomplete_scheme_classifier_;

  // The id of the UI requesting the image.
  mojom::ClientId client_id_;

  // The search query and entity ID we are searching for.
  const std::u16string search_query_;
  const std::string entity_id_;

  // The result callback to be called once we get the answer.
  base::OnceCallback<void(const GURL&)> callback_;

  // The URL loader used to get the suggestions.
  std::unique_ptr<network::SimpleURLLoader> loader_;

  base::WeakPtrFactory<SuggestEntityImageURLFetcher> weak_factory_{this};
};

ImageServiceImpl::ImageServiceImpl(
    TemplateURLService* template_url_service,
    RemoteSuggestionsService* remote_suggestions_service,
    optimization_guide::OptimizationGuideDecider* opt_guide,
    syncer::SyncService* sync_service,
    std::unique_ptr<AutocompleteSchemeClassifier>
        autocomplete_scheme_classifier)
    : template_url_service_(template_url_service),
      remote_suggestions_service_(remote_suggestions_service),
      history_consent_helper_(std::make_unique<ImageServiceConsentHelper>(
          sync_service,
          syncer::DataType::HISTORY_DELETE_DIRECTIVES)),
      bookmarks_consent_helper_(std::make_unique<ImageServiceConsentHelper>(
          sync_service,
          syncer::DataType::BOOKMARKS)),
      autocomplete_scheme_classifier_(
          std::move(autocomplete_scheme_classifier)) {
  if (opt_guide && base::FeatureList::IsEnabled(
                       kImageServiceOptimizationGuideSalientImages)) {
    opt_guide_ = opt_guide;
  }
}

ImageServiceImpl::OptGuideRequest::OptGuideRequest() = default;
ImageServiceImpl::OptGuideRequest::~OptGuideRequest() = default;
ImageServiceImpl::OptGuideRequest::OptGuideRequest(OptGuideRequest&& other) =
    default;

ImageServiceImpl::~ImageServiceImpl() = default;

base::WeakPtr<ImageService> ImageServiceImpl::GetWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

void ImageServiceImpl::FetchImageFor(mojom::ClientId client_id,
                                 const GURL& page_url,
                                 const mojom::Options& options,
                                 ResultCallback callback) {
  if (!base::FeatureList::IsEnabled(kImageService)) {
    // In general this should never happen, because each UI should have its own
    // feature gate, but this is just so we have a whole-service killswitch.
    return std::move(callback).Run(GURL());
  }

  GetConsentToFetchImage(
      client_id,
      base::BindOnce(&ImageServiceImpl::OnConsentResult, weak_factory_.GetWeakPtr(),
                     client_id, page_url, options, std::move(callback)));
}

void ImageServiceImpl::GetConsentToFetchImage(
    mojom::ClientId client_id,
    base::OnceCallback<void(PageImageServiceConsentStatus)> callback) {
  switch (client_id) {
    case mojom::ClientId::Journeys:
    case mojom::ClientId::JourneysSidePanel:
    case mojom::ClientId::HistoryEmbeddings:
    case mojom::ClientId::NtpQuests:
    case mojom::ClientId::NtpTabResumption: {
      return history_consent_helper_->EnqueueRequest(std::move(callback),
                                                     client_id);
    }
    case mojom::ClientId::NtpRealbox:
      // TODO(b/244507194): Figure out consent story for NTP realbox case.
      return std::move(callback).Run(PageImageServiceConsentStatus::kFailure);
    case mojom::ClientId::Bookmarks: {
      return bookmarks_consent_helper_->EnqueueRequest(std::move(callback),
                                                       client_id);
    }
  }
}

void ImageServiceImpl::OnConsentResult(mojom::ClientId client_id,
                                   const GURL& page_url,
                                   const mojom::Options& options,
                                   ResultCallback callback,
                                   PageImageServiceConsentStatus status) {
  base::UmaHistogramEnumeration(kConsentStatusHistogramName, status);
  base::UmaHistogramEnumeration(std::string(kConsentStatusHistogramName) + "." +
                                    ClientIdToString(client_id),
                                status);

  if (status != PageImageServiceConsentStatus::kSuccess) {
    return std::move(callback).Run(GURL());
  }

  if (options.suggest_images &&
      base::FeatureList::IsEnabled(kImageServiceSuggestPoweredImages) &&
      template_url_service_ && remote_suggestions_service_) {
    auto search_metadata =
        template_url_service_->ExtractSearchMetadata(page_url);
    // Fetch entity-keyed images for Google SRP visits only, because only
    // Google SRP visits can expect to have a reasonable entity from Google
    // Suggest.
    if (search_metadata && search_metadata->template_url &&
        search_metadata->template_url->GetEngineType(
            template_url_service_->search_terms_data()) ==
            SEARCH_ENGINE_GOOGLE) {
      UmaHistogramEnumerationForClient(
          kBackendHistogramName, PageImageServiceBackend::kSuggest, client_id);
      return FetchSuggestImage(search_metadata->template_url,
                               template_url_service_->search_terms_data(),
                               client_id,
                               /*search_query=*/search_metadata->search_terms,
                               /*entity_id=*/"", std::move(callback));
    }
  }

  if (options.optimization_guide_images && opt_guide_ &&
      base::FeatureList::IsEnabled(
          kImageServiceOptimizationGuideSalientImages)) {
    UmaHistogramEnumerationForClient(
        kBackendHistogramName, PageImageServiceBackend::kOptimizationGuide,
        client_id);
    return FetchOptimizationGuideImage(client_id, page_url,
                                       std::move(callback));
  }

  UmaHistogramEnumerationForClient(kBackendHistogramName,
                                   PageImageServiceBackend::kNoValidBackend,
                                   client_id);
  std::move(callback).Run(GURL());
}

void ImageServiceImpl::FetchSuggestImage(const TemplateURL* template_url,
                                     const SearchTermsData& search_terms_data,
                                     mojom::ClientId client_id,
                                     const std::u16string& search_query,
                                     const std::string& entity_id,
                                     ResultCallback callback) {
  auto fetcher = std::make_unique<SuggestEntityImageURLFetcher>(
      *autocomplete_scheme_classifier_, client_id, search_query, entity_id);

  // Use a raw pointer temporary so we can give ownership of the unique_ptr to
  // the callback and have a well defined SuggestEntityImageURLFetcher lifetime.
  auto* fetcher_raw_ptr = fetcher.get();
  fetcher_raw_ptr->Start(
      template_url, search_terms_data, remote_suggestions_service_,
      base::BindOnce(&ImageServiceImpl::OnSuggestImageFetched,
                     weak_factory_.GetWeakPtr(), std::move(fetcher),
                     std::move(callback)));
}

void ImageServiceImpl::OnSuggestImageFetched(
    std::unique_ptr<SuggestEntityImageURLFetcher> fetcher,
    ResultCallback callback,
    const GURL& image_url) {
  std::move(callback).Run(image_url);

  // `fetcher` is owned by this method and will be deleted now.
}

void ImageServiceImpl::FetchOptimizationGuideImage(mojom::ClientId client_id,
                                               const GURL& page_url,
                                               ResultCallback callback) {
  DCHECK(opt_guide_) << "FetchOptimizationGuideImage is never called when "
                        "opt_guide_ is nullptr.";

  OptGuideRequest request;
  request.url = page_url;
  request.callback = std::move(callback);
  auto& request_list = unsent_opt_guide_requests_[client_id];
  request_list.push_back(std::move(request));

  if (request_list.size() >=
      optimization_guide::features::
          MaxUrlsForOptimizationGuideServiceHintsFetch()) {
    // Erasing the timer also cancels the timer callback.
    opt_guide_timers_.erase(client_id);
    ProcessAllBatchedOptimizationGuideRequests(client_id);
  } else if (request_list.size() == 1U) {
    // Otherwise, if we just enqueued our FIRST request, then kick off a timer
    // to flush the queue. One millisecond is a long enough time in CPU time.
    auto timer = std::make_unique<base::OneShotTimer>();
    timer->Start(FROM_HERE, kOptimizationGuideBatchingTimeout,
                 base::BindOnce(
                     &ImageServiceImpl::ProcessAllBatchedOptimizationGuideRequests,
                     weak_factory_.GetWeakPtr(), client_id));
    opt_guide_timers_[client_id] = std::move(timer);
  }
}

void ImageServiceImpl::ProcessAllBatchedOptimizationGuideRequests(
    mojom::ClientId client_id) {
  optimization_guide::proto::RequestContext request_context;
  switch (client_id) {
    case mojom::ClientId::Journeys:
    case mojom::ClientId::JourneysSidePanel:
    case mojom::ClientId::HistoryEmbeddings: {
      request_context = optimization_guide::proto::CONTEXT_JOURNEYS;
      break;
    }
    case mojom::ClientId::NtpQuests:
    case mojom::ClientId::NtpRealbox:
    case mojom::ClientId::NtpTabResumption: {
      request_context = optimization_guide::proto::CONTEXT_NEW_TAB_PAGE;
      break;
    }
    case mojom::ClientId::Bookmarks: {
      request_context = optimization_guide::proto::CONTEXT_BOOKMARKS;
      break;
    }
  }

  std::vector<OptGuideRequest>& unsent_requests =
      unsent_opt_guide_requests_[client_id];
  if (unsent_requests.empty()) {
    return;
  }

  // Generate a list of URLs to request in this batch.
  std::vector<GURL> urls;
  for (auto& request : unsent_requests) {
    urls.push_back(request.url);
  }

  // Move the list of unsent requests to the sent vector.
  for (auto& request : unsent_requests) {
    sent_opt_guide_requests_[client_id].push_back(std::move(request));
  }
  unsent_requests.clear();

  opt_guide_->CanApplyOptimizationOnDemand(
      urls, {optimization_guide::proto::OptimizationType::SALIENT_IMAGE},
      request_context,
      base::BindRepeating(&ImageServiceImpl::OnOptimizationGuideImageFetched,
                          weak_factory_.GetWeakPtr(), client_id));
}

void ImageServiceImpl::OnOptimizationGuideImageFetched(
    mojom::ClientId client_id,
    const GURL& url,
    const base::flat_map<
        optimization_guide::proto::OptimizationType,
        optimization_guide::OptimizationGuideDecisionWithMetadata>& decisions) {
  // Extract all waiting callbacks matching `url` to `matching_callbacks`.
  std::vector<ResultCallback> matching_callbacks;
  {
    // Take over the existing whole list via a swap.
    std::vector<OptGuideRequest> all_requests;
    std::swap(all_requests, sent_opt_guide_requests_[client_id]);

    // Steal the matching callbacks, pushing back the other pending requests
    // back to the original list.
    for (auto& request : all_requests) {
      if (request.url == url) {
        matching_callbacks.push_back(std::move(request.callback));
      } else {
        sent_opt_guide_requests_[client_id].push_back(std::move(request));
      }
    }
  }

  auto iter = decisions.find(optimization_guide::proto::SALIENT_IMAGE);
  if (iter == decisions.end()) {
    UmaHistogramEnumerationForClient(
        kBackendOptimizationGuideResultHistogramName,
        PageImageServiceResult::kResponseMissing, client_id);
    return FulfillAllCallbacks(std::move(matching_callbacks), GURL());
  }

  optimization_guide::OptimizationGuideDecisionWithMetadata decision =
      iter->second;
  if (decision.decision !=
      optimization_guide::OptimizationGuideDecision::kTrue) {
    UmaHistogramEnumerationForClient(
        kBackendOptimizationGuideResultHistogramName,
        PageImageServiceResult::kNoImage, client_id);
    return FulfillAllCallbacks(std::move(matching_callbacks), GURL());
  }
  if (!decision.metadata.any_metadata().has_value()) {
    UmaHistogramEnumerationForClient(
        kBackendOptimizationGuideResultHistogramName,
        PageImageServiceResult::kResponseMalformed, client_id);
    return FulfillAllCallbacks(std::move(matching_callbacks), GURL());
  }

  auto parsed_any = optimization_guide::ParsedAnyMetadata<
      optimization_guide::proto::SalientImageMetadata>(
      decision.metadata.any_metadata().value());
  if (!parsed_any) {
    UmaHistogramEnumerationForClient(
        kBackendOptimizationGuideResultHistogramName,
        PageImageServiceResult::kResponseMalformed, client_id);
    return FulfillAllCallbacks(std::move(matching_callbacks), GURL());
  }

  // Look through the metadata, returning the first valid image URL.
  auto salient_image_metadata = *parsed_any;
  for (const auto& thumbnail : salient_image_metadata.thumbnails()) {
    if (thumbnail.has_image_url()) {
      GURL image_url(thumbnail.image_url());
      if (image_url.is_valid() && image_url.SchemeIs(url::kHttpsScheme)) {
        UmaHistogramEnumerationForClient(
            kBackendOptimizationGuideResultHistogramName,
            PageImageServiceResult::kSuccess, client_id);
        return FulfillAllCallbacks(std::move(matching_callbacks), image_url);
      }
    }
  }

  // Fail if we can't find any.
  UmaHistogramEnumerationForClient(kBackendOptimizationGuideResultHistogramName,
                                   PageImageServiceResult::kResponseMalformed,
                                   client_id);
  return FulfillAllCallbacks(std::move(matching_callbacks), GURL());
}

}  // namespace page_image_service
