// Copyright 2021 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/language/core/browser/ulp_metrics_logger.h"

#include <algorithm>

#include "base/i18n/language_tag.h"
#include "base/i18n/tag_converters.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/metrics_hashes.h"
#include "ui/base/l10n/l10n_util.h"

namespace language {

void ULPMetricsLogger::RecordInitiationLanguageCount(int count) {
  UMA_HISTOGRAM_COUNTS_100(kInitiationLanguageCountHistogram, count);
}

void ULPMetricsLogger::RecordInitiationUILanguageInULP(
    ULPLanguageStatus status) {
  UMA_HISTOGRAM_ENUMERATION(kInitiationUILanguageInULPHistogram, status);
}

void ULPMetricsLogger::RecordInitiationTranslateTargetInULP(
    ULPLanguageStatus status) {
  UMA_HISTOGRAM_ENUMERATION(kInitiationTranslateTargetInULPHistogram, status);
}

void ULPMetricsLogger::RecordInitiationTopAcceptLanguageInULP(
    ULPLanguageStatus status) {
  UMA_HISTOGRAM_ENUMERATION(kInitiationTopAcceptLanguageInULPHistogram, status);
}

void ULPMetricsLogger::RecordInitiationAcceptLanguagesULPOverlap(
    int overlap_ratio_percent) {
  UMA_HISTOGRAM_PERCENTAGE(kInitiationAcceptLanguagesULPOverlapHistogram,
                           overlap_ratio_percent);
}

void ULPMetricsLogger::RecordInitiationNeverLanguagesMissingFromULP(
    const std::vector<std::string>& never_languages) {
  for (const auto& language : never_languages) {
    base::UmaHistogramSparse(kInitiationNeverLanguagesMissingFromULP,
                             base::HashMetricName(language));
  }
}

void ULPMetricsLogger::RecordInitiationNeverLanguagesMissingFromULPCount(
    int count) {
  UMA_HISTOGRAM_COUNTS_100(kInitiationNeverLanguagesMissingFromULPCount, count);
}

void ULPMetricsLogger::RecordInitiationAcceptLanguagesPageLanguageOverlap(
    int overlap_ratio) {
  UMA_HISTOGRAM_PERCENTAGE(
      kInitiationAcceptLanguagesPageLanguageOverlapHistogram, overlap_ratio);
}
void ULPMetricsLogger::RecordInitiationPageLanguagesMissingFromULP(
    const std::vector<std::string>& page_languages) {
  for (const auto& language : page_languages) {
    base::UmaHistogramSparse(kInitiationPageLanguagesMissingFromULPHistogram,
                             base::HashMetricName(language));
  }
}
void ULPMetricsLogger::RecordInitiationPageLanguagesMissingFromULPCount(
    int count) {
  UMA_HISTOGRAM_COUNTS_100(kInitiationPageLanguagesMissingFromULPCountHistogram,
                           count);
}

ULPLanguageStatus ULPMetricsLogger::DetermineLanguageStatus(
    const std::string& language,
    const std::vector<base::i18n::LanguageTag>& ulp_languages) {
  if (language.empty() || language == "und") {
    return ULPLanguageStatus::kLanguageEmpty;
  }

  std::optional<base::i18n::LanguageTag> lang_tag =
      base::i18n::LanguageTagConverter::GetInstance().FromString(language);
  if (!lang_tag) {
    return ULPLanguageStatus::kLanguageNotInULP;
  }

  // Search for exact match of language in ulp_languages (e.g. pt-BR != pt-MZ).
  auto exact_match = std::ranges::find(ulp_languages, *lang_tag);
  if (exact_match == ulp_languages.begin()) {
    return ULPLanguageStatus::kTopULPLanguageExactMatch;
  } else if (exact_match != ulp_languages.end()) {
    return ULPLanguageStatus::kNonTopULPLanguageExactMatch;
  }

  // Now search for a base language match (e.g pt-BR == pt-MZ).
  const auto base_language = lang_tag->language_subtag();
  auto base_match = std::ranges::find_if(
      ulp_languages,
      [&base_language](const base::i18n::LanguageTag& ulp_language) {
        return base_language == ulp_language.language_subtag();
      });
  if (base_match == ulp_languages.begin()) {
    return ULPLanguageStatus::kTopULPLanguageBaseMatch;
  } else if (base_match != ulp_languages.end()) {
    return ULPLanguageStatus::kNonTopULPLanguageBaseMatch;
  }
  return ULPLanguageStatus::kLanguageNotInULP;
}

int ULPMetricsLogger::LanguagesOverlapRatio(
    const std::vector<std::string>& languages,
    const std::vector<base::i18n::LanguageTag>& compare_languages) {
  if (languages.size() <= 0) {
    return 0;
  }

  int num_overlap_languages = 0;
  for (const std::string& language : languages) {
    std::optional<base::i18n::LanguageTag> lang_tag =
        base::i18n::LanguageTagConverter::GetInstance().FromString(language);
    if (!lang_tag) {
      continue;
    }
    // Search for base matches of language (e.g. pt-BR == pt-MZ).
    const auto base_language = lang_tag->language_subtag();
    if (std::ranges::any_of(
            compare_languages,
            [&base_language](const base::i18n::LanguageTag& compare_language) {
              return base_language == compare_language.language_subtag();
            })) {
      ++num_overlap_languages;
    }
  }
  return (100 * num_overlap_languages) / languages.size();
}

std::vector<std::string> ULPMetricsLogger::RemoveULPLanguages(
    const std::vector<std::string>& languages,
    const std::vector<base::i18n::LanguageTag>& ulp_languages) {
  std::vector<std::string> filtered_languages;

  for (const auto& language : languages) {
    std::optional<base::i18n::LanguageTag> lang_tag =
        base::i18n::LanguageTagConverter::GetInstance().FromString(language);
    if (!lang_tag) {
      filtered_languages.push_back(language);
      continue;
    }
    // Only add languages that do not have a ULP base language match.
    const auto base_language = lang_tag->language_subtag();
    if (std::ranges::none_of(
            ulp_languages,
            [&base_language](const base::i18n::LanguageTag& ulp_language) {
              return base_language == ulp_language.language_subtag();
            })) {
      filtered_languages.push_back(language);
    }
  }
  return filtered_languages;
}
}  // namespace language
