// Copyright 2013 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/autofill/core/browser/data_model/addresses/autofill_profile.h"

#include <stddef.h>

#include <algorithm>
#include <array>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/check.h"
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/uuid.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/country_type.h"
#include "components/autofill/core/browser/data_model/addresses/address.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_profile_comparator.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_component.h"
#include "components/autofill/core/browser/data_model/addresses/company_info.h"
#include "components/autofill/core/browser/data_model/addresses/email_info.h"
#include "components/autofill/core/browser/data_model/addresses/name_info.h"
#include "components/autofill/core/browser/data_model/addresses/phone_number.h"
#include "components/autofill/core/browser/data_model/form_group.h"
#include "components/autofill/core/browser/data_model/usage_history_information.h"
#include "components/autofill/core/browser/data_quality/addresses/profile_token_quality.h"
#include "components/autofill/core/browser/data_quality/autofill_data_util.h"
#include "components/autofill/core/browser/data_quality/validation.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/ui/addresses/autofill_address_util.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/logging/log_buffer.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/libaddressinput/chromium/addressinput_util.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
#include "ui/base/l10n/l10n_util.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "components/autofill/android/main_autofill_jni_headers/AutofillProfile_jni.h"
#endif  // BUILDFLAG(IS_ANDROID)

using ::i18n::addressinput::AddressData;
using ::i18n::addressinput::AddressField;

namespace autofill {

namespace {

constexpr char kAddressComponentsDefaultLocality[] = "en-US";

// Returns `NAME_FULL` for first, middle, and last name field types, and groups
// phone number types similarly.
FieldType GetStorableTypeCollapsingGroups(FieldType type) {
  if (GroupTypeOfFieldType(type) == FieldTypeGroup::kName) {
    return NAME_FULL;
  }
  if (GroupTypeOfFieldType(type) == FieldTypeGroup::kPhone) {
    return PHONE_HOME_WHOLE_NUMBER;
  }
  return type;
}

// Returns a value that represents specificity/privacy of the given type. This
// is used for prioritizing which data types are shown in inferred labels. For
// example, if the profile is going to fill ADDRESS_HOME_ZIP, it should
// prioritize showing that over ADDRESS_HOME_STATE in the suggestion sublabel.
int SpecificityForType(FieldType type) {
  static constexpr auto kOrderOld =
      std::to_array({ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, EMAIL_ADDRESS,
                     PHONE_HOME_WHOLE_NUMBER, NAME_FULL, ADDRESS_HOME_ZIP,
                     ADDRESS_HOME_SORTING_CODE, COMPANY_NAME, ADDRESS_HOME_CITY,
                     ADDRESS_HOME_STATE, ADDRESS_HOME_COUNTRY});
  // Prioritizes ADDRESS_HOME_STREET_ADDRESS over postal code in inferred
  // labels. See crbug.com/540151895.
  static constexpr auto kOrderNew = std::to_array(
      {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_HOME_STREET_ADDRESS,
       EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER, NAME_FULL, ADDRESS_HOME_ZIP,
       ADDRESS_HOME_SORTING_CODE, COMPANY_NAME, ADDRESS_HOME_CITY,
       ADDRESS_HOME_STATE, ADDRESS_HOME_COUNTRY});
  CHECK_NE(type, EMPTY_TYPE);
  base::span<const FieldType> order =
      base::FeatureList::IsEnabled(
          features::kAutofillFixLabelGenerationForStreetAddress)
          ? base::span<const FieldType>(kOrderNew)
          : base::span<const FieldType>(kOrderOld);
  if (auto it = std::ranges::find(order, type); it != order.end()) {
    return it - order.begin();
  }
  // The priority of other types is arbitrary, but deterministic.
  return 100 + type;
}
// Fills `distinguishing_fields` with a list of fields to use when creating
// labels that can help to distinguish between two profiles. Draws fields from
// `suggested_fields` if it is non-NULL; otherwise returns a default list.
// If `suggested_fields` is non-NULL, does not include `excluded_fields` in the
// list. Otherwise, `excluded_fields` is ignored, and should be set to
// an empty list by convention. The resulting list of fields is sorted in
// decreasing order of importance.
void GetFieldsForDistinguishingProfiles(
    const std::vector<FieldType>* suggested_fields,
    FieldTypeSet excluded_fields,
    std::vector<FieldType>* distinguishing_fields) {
  std::vector<FieldType> default_fields;
  if (!suggested_fields) {
    default_fields.append_range(
        AutofillProfile::DefaultDistinguishingFieldsForLabels());
    if (excluded_fields.empty()) {
      distinguishing_fields->swap(default_fields);
      return;
    }
    suggested_fields = &default_fields;
  }

  // Keep track of which fields we've seen so that we avoid duplicate entries.
  // Always ignore fields of unknown type and those part of `excluded_fields`.
  FieldTypeSet seen_fields(excluded_fields, &GetStorableTypeCollapsingGroups);
  seen_fields.insert(UNKNOWN_TYPE);

  distinguishing_fields->clear();
  for (const FieldType& it : *suggested_fields) {
    FieldType suggested_type = GetStorableTypeCollapsingGroups(it);
    if (seen_fields.insert(suggested_type).second) {
      distinguishing_fields->push_back(suggested_type);
    }
  }
  std::ranges::sort(*distinguishing_fields, {}, &SpecificityForType);

  // Special case: If one of the excluded fields is a partial name (e.g.
  // `NAME_FIRST`) or phone number (e.g `PHONE_HOME_CITY_CODE`) and the
  // suggested fields include other name or phone fields fields, include
  // `NAME_FULL` or `PHONE_HOME_WHOLE_NUMBER` in the list of distinguishing
  // fields as a last-ditch fallback. This allows us to distinguish between
  // profiles that are identical except for the name or phone number.
  // TODO(crbug.com/380273791): Clean up this special case. It might be possible
  // to just append `PHONE_HOME_WHOLE_NUMBER` at the end.
  for (FieldType excluded_field : excluded_fields) {
    FieldType effective_excluded_type =
        GetStorableTypeCollapsingGroups(excluded_field);
    if (excluded_field == effective_excluded_type) {
      continue;
    }
    for (const FieldType& it : *suggested_fields) {
      if (it != excluded_field &&
          GetStorableTypeCollapsingGroups(it) == effective_excluded_type) {
        distinguishing_fields->push_back(effective_excluded_type);
        break;
      }
    }
  }
}

#if BUILDFLAG(IS_ANDROID)
// Constructs an AutofillProfile using the provided `existing_profile` as a
// foundation. In case that the `existing_profile` is invalid, an empty profile
// with a unique identifier (GUID) corresponding to the Java profile
// (`jprofile`) is initialized.
AutofillProfile CreateStarterProfile(
    const base::android::JavaRef<jobject>& jprofile,
    JNIEnv* env,
    const AutofillProfile* existing_profile) {
  std::string guid = Java_AutofillProfile_getGUID(env, jprofile);
  if (!existing_profile) {
    AutofillProfile::RecordType record_type =
        Java_AutofillProfile_getRecordType(env, jprofile);
    AddressCountryCode country_code =
        AddressCountryCode(Java_AutofillProfile_getCountryCode(env, jprofile));
    AutofillProfile profile = AutofillProfile(record_type, country_code);
    // Only set the guid if CreateStartProfile is called on an existing profile
    // (java guid not empty). Otherwise, keep the generated one.
    // TODO(crbug.com/40282123): `guid` should be always empty when existing
    // profile is not set. CHECK should be added when this condition holds.
    if (!guid.empty()) {
      profile.set_guid(guid);
    }
    return profile;
  }

  CHECK_EQ(existing_profile->guid(), guid);
  return *existing_profile;
}
#endif  // BUILDFLAG(IS_ANDROID)

}  // namespace

AutofillProfile::AutofillProfile(const std::string& guid,
                                 RecordType record_type,
                                 AddressCountryCode country_code)
    : guid_(guid),
      name_(/*alternative_names_supported=*/country_code ==
            AddressCountryCode("JP")),
      phone_number_(this),
      address_(country_code),
      record_type_(record_type),
      initial_creator_id_(kInitialCreatorChrome),
      token_quality_(this),
      usage_history_information_(/*usage_history_size=*/1) {}

AutofillProfile::AutofillProfile(RecordType record_type,
                                 AddressCountryCode country_code)
    : AutofillProfile(base::Uuid::GenerateRandomV4().AsLowercaseString(),
                      record_type,
                      country_code) {}

AutofillProfile::AutofillProfile(AddressCountryCode country_code)
    : AutofillProfile(RecordType::kLocalOrSyncable, country_code) {}

AutofillProfile::AutofillProfile(const AccountInfo& info)
    : AutofillProfile(RecordType::kAccountNameEmail,
                      i18n_model_definition::kLegacyHierarchyCountryCode) {
  SetRawInfo(NAME_FULL, base::UTF8ToUTF16(info.GetFullName().value_or("")));
  SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16(info.GetEmail()));
  FinalizeAfterImport();
}

AutofillProfile::AutofillProfile(const AutofillProfile& profile)
    : name_(/*alternative_names_supported=*/profile.GetAddressCountryCode() ==
            AddressCountryCode("JP")),
      phone_number_(this),
      address_(profile.GetAddress()),
      token_quality_(this),
      usage_history_information_(profile.usage_history_information_),
      is_devtools_testing_profile_(profile.is_devtools_testing_profile_) {
  operator=(profile);
}

AutofillProfile::~AutofillProfile() = default;

AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
  if (this == &profile) {
    return *this;
  }

  usage_history_information_.set_use_count(
      profile.usage_history_information_.use_count());
  for (size_t i = 1; i <= usage_history_information_.usage_history_size();
       ++i) {
    usage_history_information_.set_use_date(
        profile.usage_history_information_.use_date(i), i);
  }
  usage_history_information_.set_modification_date(
      profile.usage_history_information_.modification_date());

  set_guid(profile.guid());

  set_profile_label(profile.profile_label());

  name_ = profile.name_;
  email_ = profile.email_;
  company_ = profile.company_;
  phone_number_ = profile.phone_number_;
  phone_number_.set_profile(this);

  address_ = profile.address_;
  set_language_code(profile.language_code());

  record_type_ = profile.record_type_;
  initial_creator_id_ = profile.initial_creator_id_;

  token_quality_ = profile.token_quality_;
  token_quality_.set_profile(this);

  is_devtools_testing_profile_ = profile.is_devtools_testing_profile_;

  return *this;
}

#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> AutofillProfile::CreateJavaObject(
    std::string_view app_locale) const {
  JNIEnv* env = base::android::AttachCurrentThread();
  base::android::ScopedJavaLocalRef<jobject> jprofile =
      Java_AutofillProfile_Constructor(
          env, guid(), static_cast<int32_t>(record_type()), language_code());

  for (FieldType type : AutofillProfile::kDatabaseStoredTypes) {
    auto status = static_cast<int32_t>(GetVerificationStatus(type));
    // TODO(crbug.com/40278253): Reconcile usage of GetInfo and GetRawInfo
    // below.
    if (type == NAME_FULL) {
      Java_AutofillProfile_setInfo(env, jprofile, static_cast<int32_t>(type),
                                   GetInfo(type, app_locale), status);
    } else {
      Java_AutofillProfile_setInfo(env, jprofile, static_cast<int32_t>(type),
                                   GetRawInfo(type), status);
    }
  }
  return jprofile;
}

// static
AutofillProfile AutofillProfile::CreateFromJavaObject(
    const base::android::JavaRef<jobject>& jprofile,
    const AutofillProfile* existing_profile,
    std::string_view app_locale) {
  JNIEnv* env = base::android::AttachCurrentThread();
  AutofillProfile profile =
      CreateStarterProfile(jprofile, env, existing_profile);

  std::vector<int> field_types =
      Java_AutofillProfile_getFieldTypes(env, jprofile);

  std::vector<std::tuple<FieldType, std::u16string, VerificationStatus>>
      modified_fields;
  for (int int_field_type : field_types) {
    FieldType field_type =
        ToSafeFieldType(int_field_type).value_or(NO_SERVER_DATA);
    CHECK(field_type != NO_SERVER_DATA);
    VerificationStatus status =
        Java_AutofillProfile_getInfoStatus(env, jprofile, field_type);
    std::u16string value =
        Java_AutofillProfile_getInfo(env, jprofile, field_type);

    if (value != profile.GetInfo(field_type, app_locale) ||
        status != profile.GetVerificationStatus(field_type)) {
      modified_fields.emplace_back(field_type, value, status);
    }
  }

  for (const auto& field_data : modified_fields) {
    const auto& [field_type, value, status] = field_data;
    // TODO(crbug.com/40278253): Reconcile usage of GetInfo and GetRawInfo
    // below.
    if (field_type == NAME_FULL || field_type == ADDRESS_HOME_COUNTRY) {
      profile.SetInfoWithVerificationStatus(field_type, value, app_locale,
                                            status);
    } else {
      profile.SetRawInfoWithVerificationStatus(field_type, value, status);
    }
  }

  profile.set_language_code(
      Java_AutofillProfile_getLanguageCode(env, jprofile));
  profile.FinalizeAfterImport();

  return profile;
}
#endif  // BUILDFLAG(IS_ANDROID)

double AutofillProfile::GetRankingScore(base::Time current_time) const {
  return usage_history_information_.GetRankingScore(current_time);
}

bool AutofillProfile::HasGreaterRankingThan(const AutofillProfile* other,
                                            base::Time comparison_time) const {
  return usage_history_information_.HasGreaterRankingThan(
      other->usage_history_information_, comparison_time);
}

void AutofillProfile::GetMatchingTypes(std::u16string_view text,
                                       std::string_view app_locale,
                                       FieldTypeSet* matching_types) const {
  FieldTypeSet matching_types_in_this_profile;
  for (const auto* form_group : FormGroups()) {
    form_group->GetMatchingTypes(text, app_locale,
                                 &matching_types_in_this_profile);
  }

  for (auto type : matching_types_in_this_profile) {
    matching_types->insert(type);
  }
}

std::u16string AutofillProfile::GetRawInfo(FieldType type) const {
  const FormGroup* form_group = FormGroupForType(type);
  return form_group ? form_group->GetRawInfo(type) : std::u16string();
}

void AutofillProfile::SetRawInfoWithVerificationStatus(
    FieldType type,
    std::u16string_view value,
    VerificationStatus status) {
  FormGroup* form_group = MutableFormGroupForType(type);
  if (form_group) {
    if (type == ADDRESS_HOME_COUNTRY) {
      auto old_country_code = GetAddressCountryCode();
      form_group->SetRawInfoWithVerificationStatus(type, value, status);
      OnProfileCountryUpdate(old_country_code, GetAddressCountryCode());
      return;
    }

    form_group->SetRawInfoWithVerificationStatus(type, value, status);
  }
}

FieldTypeSet AutofillProfile::GetSupportedTypes() const {
  FieldTypeSet supported_types;
  for (const FormGroup* form_group : FormGroups()) {
    supported_types.insert_all(form_group->GetSupportedTypes());
  }
  return supported_types;
}

FieldType AutofillProfile::GetStorableTypeOf(FieldType type) const {
  const FieldTypeGroup group = GroupTypeOfFieldType(type);
  if (group == FieldTypeGroup::kAddress) {
    return address_.GetRoot().GetStorableTypeOf(type).value_or(type);
  } else if (group == FieldTypeGroup::kName) {
    return name_.GetStorableTypeOf(type).value_or(type);
  } else if (group == FieldTypeGroup::kPhone) {
    // The only storable phone number type is PHONE_HOME_WHOLE_NUMBER.
    return PHONE_HOME_WHOLE_NUMBER;
  } else {
    // The other FieldTypeGroups only support storable types.
    return type;
  }
}

FieldTypeSet AutofillProfile::GetUserVisibleTypes() const {
  FieldTypeSet visible_types{PHONE_HOME_WHOLE_NUMBER, EMAIL_ADDRESS};
  std::string components_language_code;
  for (const AutofillAddressUIComponent& component : GetAddressComponents(
           GetAddressCountryCode().value(), kAddressComponentsDefaultLocality,
           /*enable_field_labels_localization=*/false,
           /*include_literals=*/false, components_language_code)) {
    visible_types.insert(component.field);
  }

  return visible_types;
}

bool AutofillProfile::IsEmpty(std::string_view app_locale) const {
  FieldTypeSet types;
  GetNonEmptyTypes(app_locale, &types);
  return types.empty();
}

int AutofillProfile::Compare(const AutofillProfile& profile) const {
  static constexpr auto kTypes =
      std::to_array<FieldType>({NAME_FULL,
                                NAME_FIRST,
                                NAME_MIDDLE,
                                NAME_LAST,
                                NAME_LAST_FIRST,
                                NAME_LAST_SECOND,
                                NAME_LAST_CONJUNCTION,
                                ALTERNATIVE_FULL_NAME,
                                ALTERNATIVE_GIVEN_NAME,
                                ALTERNATIVE_FAMILY_NAME,
                                COMPANY_NAME,
                                ADDRESS_HOME_STREET_ADDRESS,
                                ADDRESS_HOME_DEPENDENT_LOCALITY,
                                ADDRESS_HOME_CITY,
                                ADDRESS_HOME_STATE,
                                ADDRESS_HOME_ZIP,
                                ADDRESS_HOME_ZIP_AND_CITY,
                                ADDRESS_HOME_SORTING_CODE,
                                ADDRESS_HOME_COUNTRY,
                                ADDRESS_HOME_LANDMARK,
                                ADDRESS_HOME_OVERFLOW,
                                ADDRESS_HOME_STREET_LOCATION_AND_LOCALITY,
                                ADDRESS_HOME_BETWEEN_STREETS_OR_LANDMARK,
                                ADDRESS_HOME_OVERFLOW_AND_LANDMARK,
                                ADDRESS_HOME_BETWEEN_STREETS,
                                ADDRESS_HOME_BETWEEN_STREETS_1,
                                ADDRESS_HOME_BETWEEN_STREETS_2,
                                ADDRESS_HOME_ADMIN_LEVEL2,
                                ADDRESS_HOME_HOUSE_NUMBER,
                                ADDRESS_HOME_STREET_NAME,
                                ADDRESS_HOME_SUBPREMISE,
                                ADDRESS_HOME_STREET_LOCATION,
                                ADDRESS_HOME_APT,
                                ADDRESS_HOME_APT_NUM,
                                ADDRESS_HOME_APT_TYPE,
                                ADDRESS_HOME_FLOOR,
                                EMAIL_ADDRESS,
                                PHONE_HOME_WHOLE_NUMBER});

  // When adding field types, ensure that they don't need to be added here and
  // update the last checked value.
  static_assert(FieldType::MAX_VALID_FIELD_TYPE == 220,
                "New field type needs to be reviewed for inclusion in the "
                "profile comparison logic.");

  for (FieldType type : kTypes) {
    int comparison = GetRawInfo(type).compare(profile.GetRawInfo(type));
    if (comparison != 0) {
      return comparison;
    }

    // If the value is empty, the verification status can be ambiguous because
    // the value could be either build from its empty child nodes or parsed
    // from its parent. Therefore, it should not be considered when evaluating
    // the similarity of two profiles.
    if (profile.GetRawInfo(type).empty()) {
      continue;
    }

    if (IsLessSignificantVerificationStatus(
            GetVerificationStatus(type), profile.GetVerificationStatus(type))) {
      return -1;
    }
    if (IsLessSignificantVerificationStatus(profile.GetVerificationStatus(type),
                                            GetVerificationStatus(type))) {
      return 1;
    }
  }

  return 0;
}

bool AutofillProfile::EqualsForLegacySyncPurposes(
    const AutofillProfile& profile) const {
  return usage_history_information_.use_count() ==
             profile.usage_history_information_.use_count() &&
         usage_history_information_.UseDateEqualsInSeconds(
             profile.usage_history()) &&
         EqualsSansGuid(profile);
}

bool AutofillProfile::EqualsForUpdatePurposes(
    const AutofillProfile& new_profile) const {
  return usage_history_information_.use_count() ==
             new_profile.usage_history_information_.use_count() &&
         usage_history_information_.UseDateEqualsInSeconds(
             new_profile.usage_history()) &&
         language_code() == new_profile.language_code() &&
         token_quality() == new_profile.token_quality() &&
         Compare(new_profile) == 0;
}

bool AutofillProfile::operator==(const AutofillProfile& profile) const {
  return guid() == profile.guid() && EqualsSansGuid(profile);
}

bool AutofillProfile::IsSubsetOf(const AutofillProfileComparator& comparator,
                                 const AutofillProfile& profile) const {
  return IsSubsetOfForFieldSet(comparator, profile,
                               AutofillProfile::kDatabaseStoredTypes);
}

bool AutofillProfile::IsSubsetOfForFieldSet(
    const AutofillProfileComparator& comparator,
    const AutofillProfile& profile,
    const FieldTypeSet& types) const {
  SCOPED_UMA_HISTOGRAM_TIMER("Autofill.Timing.IsSubsetOfForFieldSet");

  // Do not process `profile` if it is trivially unrelated to `this` for having
  // different source country code, for performance reasons.
  if (types.contains(ADDRESS_HOME_COUNTRY) &&
      !data_util::HaveNonConflictingCountryCodes(
          GetAddressCountryCode(), profile.GetAddressCountryCode())) {
    return false;
  }

  const std::string& app_locale = comparator.app_locale();
  const AddressComponent& address = GetAddress().GetRoot();
  const AddressComponent& other_address = profile.GetAddress().GetRoot();

  for (FieldType type : types) {
    // Prefer GetInfo over GetRawInfo so that a reasonable value is retrieved
    // when the raw data is empty or unnormalized. For example, suppose a
    // profile's first and last names are set but its full name is not set.
    // GetInfo for the NAME_FULL type returns the constituent name parts;
    // however, GetRawInfo returns an empty string.
    const std::u16string value = GetInfo(type, app_locale);
    const std::u16string other_value = profile.GetInfo(type, app_locale);
    if (value.empty() || value == other_value || type == ADDRESS_HOME_COUNTRY) {
      continue;
    }
    // TODO(crbug.com/40257475): Use rewriter rules for all kAddressHome types.
    if (type == ADDRESS_HOME_STREET_ADDRESS || type == ADDRESS_HOME_LINE1 ||
        type == ADDRESS_HOME_LINE2 || type == ADDRESS_HOME_LINE3) {
      // This will compare street addresses after applying appropriate address
      // rewriter rules to both values, so that for example US streets like
      // `Main Street` and `main st` evaluate to equal.
      const AddressCountryCode common_country_code =
          AddressComponent::GetCommonCountry(address.GetCountryCode(),
                                             other_address.GetCountryCode());
      if (address.GetValueForComparisonForType(type, common_country_code) !=
          other_address.GetValueForComparisonForType(type,
                                                     common_country_code)) {
        return false;
      }
    } else if (type == NAME_FULL) {
      if (!profile.GetNameInfo().IsNameVariantOf(value, app_locale)) {
        // Check whether the full name of |this| can be derived from the full
        // name of |profile| if the form contains a full name field.
        //
        // Suppose the full name of |this| is Mia Park and |profile|'s full name
        // is Mia L Park. Mia Park can be derived from Mia L Park, so |this|
        // could be a subset of |profile|.
        //
        // If the form contains fields for a name's constituent parts, e.g.
        // NAME_FIRST, then these values are compared according to the
        // conditions that follow.
        return false;
      }
    } else if (type == PHONE_HOME_WHOLE_NUMBER ||
               type == PHONE_HOME_CITY_AND_NUMBER) {
      if (!i18n::PhoneNumbersMatch(
              value, other_value,
              base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
              app_locale)) {
        return false;
      }
    } else if (type == EMAIL_ADDRESS) {
      if (!AutofillProfileComparator::Compare(
              value, other_value, normalization::WhitespaceSpec::kRetain)) {
        return false;
      }
    } else if (!AutofillProfileComparator::Compare(
                   value, other_value,
                   normalization::WhitespaceSpec::kDiscard)) {
      return false;
    }
  }
  return true;
}

bool AutofillProfile::IsStrictSupersetOf(
    const AutofillProfileComparator& comparator,
    const AutofillProfile& profile) const {
  return profile.IsSubsetOf(comparator, *this) &&
         !IsSubsetOf(comparator, profile);
}

AddressCountryCode AutofillProfile::GetAddressCountryCode() const {
  return GetAddress().GetAddressCountryCode();
}

bool AutofillProfile::IsAccountProfile() const {
  switch (record_type()) {
    case RecordType::kLocalOrSyncable:
      return false;
    case RecordType::kAccount:
    case RecordType::kAccountHome:
    case RecordType::kAccountWork:
    case RecordType::kAccountNameEmail:
      return true;
  }
  NOTREACHED();
}

bool AutofillProfile::IsHomeAndWorkProfile() const {
  switch (record_type()) {
    case RecordType::kLocalOrSyncable:
    case RecordType::kAccount:
    case RecordType::kAccountNameEmail:
      return false;
    case RecordType::kAccountHome:
    case RecordType::kAccountWork:
      return true;
  }
  NOTREACHED();
}

void AutofillProfile::OverwriteDataFromForLegacySync(
    const AutofillProfile& profile) {
  DCHECK_EQ(guid(), profile.guid());

  // Some fields should not got overwritten by empty values; back-up the
  // values.
  std::string language_code_value = language_code();

  // Structured names should not be simply overwritten but it should be
  // attempted to merge the names.
  bool is_structured_name_mergeable = false;
  NameInfo name_info = GetNameInfo();
  is_structured_name_mergeable =
      name_info.IsStructuredNameMergeable(profile.GetNameInfo());
  name_info.MergeStructuredName(
      profile.GetNameInfo(),
      usage_history().use_date() < profile.usage_history().use_date());

  // ProfileTokenQuality is not synced through legacy sync - and as a result,
  // `profile` has no observations. Make sure that observations for token values
  // that haven't changed are kept.
  ProfileTokenQuality token_quality = std::move(token_quality_);
  token_quality.ResetObservationsForDifferingTokens(profile);

  *this = profile;

  if (language_code().empty()) {
    set_language_code(language_code_value);
  }

  // For structured names, use the merged name if possible.
  // If the full name of |profile| is empty, maintain the complete name
  // structure. Note, this should only happen if the complete name is empty. For
  // the legacy implementation, set the full name if |profile| does not contain
  // a full name.
  if (is_structured_name_mergeable || !HasRawInfo(NAME_FULL)) {
    name_ = std::move(name_info);
  }

  token_quality_ = std::move(token_quality);
}

AutofillProfile::ProfileMergeResult AutofillProfile::MergeDataFrom(
    const AutofillProfile& profile,
    std::string_view app_locale) {
  // TODO(crbug.com/453945181) Move this CHECK to a more suitable place.
  CHECK(record_type() != RecordType::kAccountNameEmail ||
        profile.record_type() != RecordType::kAccountNameEmail);

  if (!data_util::HaveNonConflictingCountryCodes(
          GetAddressCountryCode(), profile.GetAddressCountryCode())) {
    return ProfileMergeResult::kMergeFailed;
  }

  // TODO(crbug.com/453945181): Change check and merge logic for `NameInfo` so
  // it conforms to the other infos. The check logic should be embedded inside
  // the merge method.
  if (!NameInfo::AreNamesMergeable(profile.GetNameInfo(),
                                   profile.GetAddressCountryCode(),
                                   GetNameInfo(), GetAddressCountryCode()) ||
      !NameInfo::AreAlternativeNamesMergeable(
          profile.GetNameInfo(), profile.GetAddressCountryCode(), GetNameInfo(),
          GetAddressCountryCode())) {
    return ProfileMergeResult::kMergeFailed;
  }

  AutofillProfileComparator comparator(app_locale);

  NameInfo name(
      /*alternative_names_supported=*/profile.GetAddressCountryCode() ==
      AddressCountryCode("JP"));
  EmailInfo email;
  CompanyInfo company;
  PhoneNumber phone_number(this);
  Address address(profile.GetAddressCountryCode());

  DVLOG(1) << "Merging profiles:\nSource = " << profile << "\nDest = " << *this;

  // The comparator's merge operations are biased to prefer the data in the
  // first profile parameter when the data is the same modulo case. We expect
  // the caller to pass the incoming profile in this position to prefer
  // accepting updates instead of preserving the original data. I.e., passing
  // the incoming profile first accepts case and diacritic changes, for example,
  // the other ways does not.
  // TODO(crbug.com/453945181): Simplify this logic by returning merged
  // objects instead of passing them by reference.
  // TODO(crbug.com/453945181): Change check and merge logic for `NameInfo` so
  // it conforms to the other infos. The check logic should be embedded inside
  // the merge method.
  if (!NameInfo::MergeNames(
          profile.GetNameInfo(), profile.GetAddressCountryCode(), GetNameInfo(),
          GetAddressCountryCode(),
          usage_history().use_date() < profile.usage_history().use_date(),
          name) ||
      comparator.MergeEmailAddresses(profile, *this, email) ==
          ProfileMergeResult::kMergeFailed ||
      comparator.MergeCompanyNames(profile, *this, company) ==
          ProfileMergeResult::kMergeFailed ||
      comparator.MergePhoneNumbers(profile, *this, phone_number) ==
          ProfileMergeResult::kMergeFailed ||
      comparator.MergeAddresses(profile, *this, address) ==
          ProfileMergeResult::kMergeFailed) {
    return ProfileMergeResult::kMergeFailed;
  }

  set_language_code(profile.language_code());

  usage_history_information_.MergeUsageHistories(profile.usage_history());

  // Update the fields which need to be modified, if any. Note: that we're
  // comparing the fields for representational equality below (i.e., are the
  // values byte for byte the same).

  bool modified = false;

  if (name_ != name) {
    MergeFormGroupTokenQuality(name, profile);
    name_ = name;
    modified = true;
  }

  if (email_ != email) {
    MergeFormGroupTokenQuality(email, profile);
    email_ = email;
    modified = true;
  }

  if (company_ != company) {
    MergeFormGroupTokenQuality(company, profile);
    company_ = company;
    modified = true;
  }

  if (phone_number_ != phone_number) {
    MergeFormGroupTokenQuality(phone_number, profile);
    phone_number_ = phone_number;
    modified = true;
  }

  if (address_ != address) {
    MergeFormGroupTokenQuality(address, profile);
    address_ = address;
    modified = true;
  }

  return modified ? ProfileMergeResult::kMergeSucceededWithModification
                  : ProfileMergeResult::kMergeSucceededWithoutModification;
}

void AutofillProfile::MergeFormGroupTokenQuality(
    const FormGroup& merged_group,
    const AutofillProfile& other_profile) {
  for (FieldType type : merged_group.GetSupportedTypes()) {
    const std::u16string& merged_value = merged_group.GetRawInfo(type);
    if (!AutofillProfile::kDatabaseStoredTypes.contains(type) ||
        merged_value == GetRawInfo(type)) {
      // Quality information is only tracked for stored types. If the merged
      // value matches the existing value, its token quality is kept.
      continue;
    }
    if (merged_value == other_profile.GetRawInfo(type)) {
      // The merged value comes from the `other_profile`, so its token quality
      // is carried over.
      token_quality_.CopyObservationsForStoredType(
          type, other_profile.token_quality_);
    } else {
      // The `merged_value` matches neither `*this` nor the `other_profile`'s
      // value, because the values were combined in some way. This generally
      // doesn't happen, because the merging logic only merges values if one is
      // a subset/substring of the other. However, in some cases, formatting
      // differences can make this case reachable. For example, merging the
      // phone numbers "5550199" and "555.0199" gives "555-0199".
      // Since observations cannot be merged, reset the token quality.
      token_quality_.ResetObservationsForStoredType(type);
    }
  }
}

void AutofillProfile::OnProfileCountryUpdate(
    const AddressCountryCode& old_country_code,
    const AddressCountryCode& new_country_code) {
  if (old_country_code == new_country_code) {
    return;
  }

  name_.OnCountryChange(new_country_code);
}

// static
base::span<const FieldType>
AutofillProfile::DefaultDistinguishingFieldsForLabels() {
  static constexpr auto kDefaultDistinguishingFieldsForLabelsOld =
      std::to_array<FieldType>(
          {NAME_FULL, ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2,
           ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_CITY,
           ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE,
           ADDRESS_HOME_COUNTRY, EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER,
           COMPANY_NAME});
  static constexpr auto kDefaultDistinguishingFieldsForLabelsNew =
      std::to_array<FieldType>({NAME_FULL, ADDRESS_HOME_STREET_ADDRESS,
                                ADDRESS_HOME_DEPENDENT_LOCALITY,
                                ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
                                ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE,
                                ADDRESS_HOME_COUNTRY, EMAIL_ADDRESS,
                                PHONE_HOME_WHOLE_NUMBER, COMPANY_NAME});
  return base::FeatureList::IsEnabled(
             features::kAutofillFixLabelGenerationForStreetAddress)
             ? base::span<const FieldType>(
                   kDefaultDistinguishingFieldsForLabelsNew)
             : base::span<const FieldType>(
                   kDefaultDistinguishingFieldsForLabelsOld);
}

// static
std::vector<std::u16string> AutofillProfile::CreateDifferentiatingLabels(
    base::span<const AutofillProfile* const> profiles,
    std::string_view app_locale) {
  const size_t kMinimalFieldsShown = 2;
  return CreateInferredLabels(profiles, /*suggested_fields=*/std::nullopt,
                              /*excluded_fields=*/{}, kMinimalFieldsShown,
                              app_locale);
}

// static
std::vector<std::u16string> AutofillProfile::CreateInferredLabels(
    base::span<const AutofillProfile* const> profiles,
    const std::optional<FieldTypeSet> suggested_fields,
    FieldTypeSet excluded_fields,
    size_t minimal_fields_shown,
    std::string_view app_locale) {
  std::vector<FieldType> fields_to_use;
  std::vector<FieldType> suggested_fields_types =
      suggested_fields
          ? std::vector(suggested_fields->begin(), suggested_fields->end())
          : std::vector<FieldType>();
  GetFieldsForDistinguishingProfiles(
      suggested_fields ? &suggested_fields_types : nullptr, excluded_fields,
      &fields_to_use);

  // Construct the default label for each profile. Also construct a map that
  // associates each label with the profiles that have this info. This map is
  // then used to detect which labels need further differentiating fields. Note
  // that the actual displayed label might slightly differ due to formatting,
  // but it is not needed to format the text for differentiating the labels.
  std::map<std::u16string, std::list<size_t>> labels_to_profiles;
  for (size_t i = 0; i < profiles.size(); ++i) {
    std::u16string label = profiles[i]->ConstructInferredLabel(
        fields_to_use, minimal_fields_shown, app_locale);
    labels_to_profiles[label].push_back(i);
  }

  std::vector<std::u16string> labels;
  labels.resize(profiles.size());
  for (auto& it : labels_to_profiles) {
    if (it.second.size() == 1) {
      // This label is unique, so use it without any further ado.
      size_t profile_index = it.second.front();
      labels[profile_index] = it.first;
    } else {
      // We have more than one profile with the same label, so add
      // differentiating fields.
      CreateInferredLabelsHelper(profiles, it.second, fields_to_use,
                                 minimal_fields_shown, app_locale, labels);
    }
  }
  return labels;
}

std::u16string AutofillProfile::ConstructInferredLabel(
    base::span<const FieldType> included_fields,
    size_t num_fields_to_use,
    std::string_view app_locale) const {
  // TODO(estade): use libaddressinput?
  std::u16string separator =
      l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);

  const std::u16string& profile_region_code = GetInfo(
      AutofillType(ADDRESS_HOME_COUNTRY, /*is_country_code=*/true), app_locale);
  std::string address_region_code = base::UTF16ToUTF8(profile_region_code);

  // A copy of |this| pruned down to contain only data for the address fields in
  // |included_fields|.
  AutofillProfile trimmed_profile(guid(), RecordType::kLocalOrSyncable,
                                  GetAddressCountryCode());
  trimmed_profile.SetInfo(
      AutofillType(ADDRESS_HOME_COUNTRY, /*is_country_code=*/true),
      profile_region_code, app_locale);
  trimmed_profile.set_language_code(language_code());
  AutofillCountry country(address_region_code);

  std::vector<FieldType> remaining_fields;
  for (size_t i = 0; i < included_fields.size() && num_fields_to_use > 0; ++i) {
    if (!country.IsAddressFieldSettingAccessible(included_fields[i]) ||
        included_fields[i] == ADDRESS_HOME_COUNTRY) {
      remaining_fields.push_back(included_fields[i]);
      continue;
    }

    std::u16string field_value = GetInfo(included_fields[i], app_locale);
    if (field_value.empty()) {
      continue;
    }
    trimmed_profile.SetInfo(included_fields[i], field_value, app_locale);
    --num_fields_to_use;
  }

  std::unique_ptr<AddressData> address_data =
      i18n::CreateAddressDataFromAutofillProfile(trimmed_profile, app_locale);
  std::string address_line;
  ::i18n::addressinput::GetFormattedNationalAddressLine(*address_data,
                                                        &address_line);
  std::u16string label = base::UTF8ToUTF16(address_line);

  for (std::vector<FieldType>::const_iterator it = remaining_fields.begin();
       it != remaining_fields.end() && num_fields_to_use > 0; ++it) {
    std::u16string field_value;
    // Special case whole numbers: we want the user-formatted (raw) version, not
    // the canonicalized version we'll fill into the page.
    if (*it == PHONE_HOME_WHOLE_NUMBER) {
      field_value = GetRawInfo(*it);
    } else {
      field_value = GetInfo(*it, app_locale);
    }
    if (field_value.empty()) {
      continue;
    }

    if (!label.empty()) {
      label.append(separator);
    }

    label.append(field_value);
    --num_fields_to_use;
  }

  // If country code is missing, libaddressinput won't be used to format the
  // address. In this case the suggestion might include a multi-line street
  // address which needs to be flattened.
  base::ReplaceChars(label, u"\n", separator, &label);

  return label;
}

void AutofillProfile::RecordAndLogUse() {
  const base::Time now = AutofillClock::Now();
  const base::TimeDelta time_since_last_used =
      now - usage_history_information_.use_date();
  usage_history_information_.RecordUseDate(now);
  // Ensure that use counts are not skewed by multiple filling operations of the
  // form. This is especially important for forms fully annotated with
  // autocomplete=unrecognized. For such forms, keyboard accessory chips only
  // fill a single field at a time as per
  // `AutofillSuggestionsForAutocompleteUnrecognizedFieldsOnMobile`.
  if (time_since_last_used.InSeconds() >= 60) {
    if (usage_history_information_.use_count() == 1) {
      // The max is the number of days a profile wasn't used before it gets
      // deleted (see `kDisusedDataModelDeletionTimeDelta`).
      base::UmaHistogramCustomCounts("Autofill.DaysUntilFirstUsage.Profile",
                                     time_since_last_used.InDays(), 1, 395,
                                     100);
    }
    usage_history_information_.set_use_count(
        usage_history_information_.use_count() + 1);
    UMA_HISTOGRAM_COUNTS_1000("Autofill.DaysSinceLastUse.Profile",
                              time_since_last_used.InDays());
  }
  LogVerificationStatuses();
}

void AutofillProfile::LogVerificationStatuses() {
  AutofillMetrics::LogVerificationStatusOfNameTokensOnProfileUsage(*this);
  AutofillMetrics::LogVerificationStatusOfAddressTokensOnProfileUsage(*this);
}

VerificationStatus AutofillProfile::GetVerificationStatus(
    const FieldType type) const {
  const FormGroup* form_group = FormGroupForType(type);
  if (!form_group) {
    return VerificationStatus::kNoStatus;
  }

  return form_group->GetVerificationStatus(type);
}

std::u16string AutofillProfile::GetInfo(const AutofillType& type,
                                        std::string_view app_locale) const {
  const FormGroup* form_group = FormGroupForType(type.GetAddressType());
  if (!form_group) {
    return std::u16string();
  }
  return form_group->GetInfo(type, app_locale);
}

bool AutofillProfile::SetInfoWithVerificationStatus(const AutofillType& type,
                                                    std::u16string_view value,
                                                    std::string_view app_locale,
                                                    VerificationStatus status) {
  FormGroup* form_group = MutableFormGroupForType(type.GetAddressType());
  if (!form_group) {
    return false;
  }

  const std::u16string_view trimmed_value =
      base::TrimWhitespace(value, base::TRIM_ALL);
  if (type.GetAddressType() == ADDRESS_HOME_COUNTRY) {
    const AddressCountryCode old_country_code = GetAddressCountryCode();
    const bool response = form_group->SetInfoWithVerificationStatus(
        type, trimmed_value, app_locale, status);
    OnProfileCountryUpdate(old_country_code, GetAddressCountryCode());
    return response;
  }

  return form_group->SetInfoWithVerificationStatus(type, trimmed_value,
                                                   app_locale, status);
}

bool AutofillProfile::SetInfoWithVerificationStatus(FieldType type,
                                                    std::u16string_view value,
                                                    std::string_view app_locale,
                                                    VerificationStatus status) {
  return SetInfoWithVerificationStatus(AutofillType(type), value, app_locale,
                                       status);
}

// static
void AutofillProfile::CreateInferredLabelsHelper(
    base::span<const AutofillProfile* const> profiles,
    const std::list<size_t>& indices,
    const std::vector<FieldType>& field_types,
    size_t num_fields_to_include,
    std::string_view app_locale,
    std::vector<std::u16string>& labels) {
  // For efficiency, we first construct a map of fields to their text values and
  // each value's frequency.
  std::map<FieldType, std::map<std::u16string, size_t>>
      field_text_frequencies_by_field;
  for (const FieldType& field_type : field_types) {
    std::map<std::u16string, size_t>& field_text_frequencies =
        field_text_frequencies_by_field[field_type];

    for (const auto& it : indices) {
      const AutofillProfile* profile = profiles[it];
      std::u16string field_text = profile->GetInfo(field_type, app_locale);

      // If this label is not already in the map, add it with frequency 0.
      if (!field_text_frequencies.contains(field_text)) {
        field_text_frequencies[field_text] = 0;
      }

      // Now, increment the frequency for this label.
      ++field_text_frequencies[field_text];
    }
  }

  // Now comes the meat of the algorithm. For each profile, we scan the list of
  // fields to use, looking for two things:
  //  1. A (non-empty) field that differentiates the profile from all others
  //  2. At least |num_fields_to_include| non-empty fields
  // Before we've satisfied condition (2), we include all fields, even ones that
  // are identical across all the profiles. Once we've satisfied condition (2),
  // we only include fields that that have at last two distinct values.
  for (const auto& it : indices) {
    const AutofillProfile* profile = profiles[it];

    std::vector<FieldType> label_fields;
    bool found_differentiating_field = false;
    for (FieldType field_type : field_types) {
      // Skip over empty fields.
      std::u16string field_text = profile->GetInfo(field_type, app_locale);
      if (field_text.empty()) {
        continue;
      }

      std::map<std::u16string, size_t>& field_text_frequencies =
          field_text_frequencies_by_field[field_type];

      bool current_field_is_differentiating =
          !field_text_frequencies.contains(u"") &&
          field_text_frequencies[field_text] == 1;
      found_differentiating_field |= current_field_is_differentiating;

      // Once we've found enough non-empty fields, skip over any remaining
      // fields that are identical across all the profiles.
      if (label_fields.size() >= num_fields_to_include &&
          field_text_frequencies.size() == 1) {
        continue;
      }

      label_fields.push_back(field_type);

      // If we've (1) found a differentiating field and (2) found at least
      // |num_fields_to_include| non-empty fields, we're done!
      if (found_differentiating_field &&
          label_fields.size() >= num_fields_to_include) {
        break;
      }
    }

    // The final order of the `label_fields` is established by a third party
    // library: libaddressinput. Libaddressinput has a different order for each
    // country, depending on what makes sense in that country. Chrome code has
    // no control over the final order of the labels.
    labels[it] = profile->ConstructInferredLabel(
        label_fields, label_fields.size(), app_locale);
  }
}

const FormGroup* AutofillProfile::FormGroupForType(FieldType type) const {
  return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
}

FormGroup* AutofillProfile::MutableFormGroupForType(FieldType type) {
  switch (GroupTypeOfFieldType(type)) {
    case FieldTypeGroup::kName:
      return &name_;
    case FieldTypeGroup::kEmail:
      return &email_;
    case FieldTypeGroup::kCompany:
      return &company_;
    case FieldTypeGroup::kPhone:
      return &phone_number_;
    case FieldTypeGroup::kAddress:
      return &address_;
    case FieldTypeGroup::kNoGroup:
    case FieldTypeGroup::kCreditCard:
    case FieldTypeGroup::kIban:
    case FieldTypeGroup::kPasswordField:
    case FieldTypeGroup::kUsernameField:
    case FieldTypeGroup::kTransaction:
    case FieldTypeGroup::kStandaloneCvcField:
    case FieldTypeGroup::kUnfillable:
    case FieldTypeGroup::kAutofillAi:
    case FieldTypeGroup::kLoyaltyCard:
    case FieldTypeGroup::kOneTimePassword:
      return nullptr;
  }
  NOTREACHED();
}

bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const {
  return language_code() == profile.language_code() &&
         profile_label() == profile.profile_label() &&
         record_type() == profile.record_type() && Compare(profile) == 0;
}

std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
  os << profile.guid() << " label: " << profile.profile_label() << " "
     << profile.usage_history().use_count() << " "
     << profile.usage_history().use_date() << " " << profile.language_code()
     << std::endl;

  for (FieldType type : profile.GetSupportedTypes()) {
    os << FieldTypeToStringView(type) << ": " << profile.GetRawInfo(type) << "("
       << profile.GetVerificationStatus(type) << ")" << std::endl;
  }

  return os;
}

LogBuffer& operator<<(LogBuffer& buffer, const AutofillProfile& profile) {
  auto get_record_type = [](AutofillProfile::RecordType record_type) {
    switch (record_type) {
      case AutofillProfile::RecordType::kLocalOrSyncable:
        return "kLocalOrSyncable";
      case AutofillProfile::RecordType::kAccount:
        return "kAccount";
      case AutofillProfile::RecordType::kAccountHome:
        return "kAccountHome";
      case AutofillProfile::RecordType::kAccountWork:
        return "kAccountWork";
      case AutofillProfile::RecordType::kAccountNameEmail:
        return "kAccountNameEmail";
    }
    NOTREACHED();
  };
  buffer << Tag{"table"};
  buffer << Tr{} << "guid" << profile.guid_;
  buffer << Tr{} << "record_type" << get_record_type(profile.record_type_);
  buffer << Tr{} << "name" << profile.name_;
  buffer << Tr{} << "address" << profile.address_;
  buffer << Tr{} << "email" << profile.email_;
  buffer << Tr{} << "company" << profile.company_;
  buffer << Tr{} << "phone" << profile.phone_number_;
  buffer << CTag{"table"};
  return buffer;
}

bool AutofillProfile::FinalizeAfterImport() {
  bool success = true;
  success &= name_.FinalizeAfterImport();
  success &= address_.FinalizeAfterImport();
  return success;
}

AutofillProfile AutofillProfile::ConvertToAccountProfile() const {
  DCHECK(record_type() != RecordType::kAccount);
  AutofillProfile account_profile = *this;
  // Since GUIDs are assumed to be unique across all profile record types, a new
  // GUID is assigned.
  account_profile.set_guid(base::Uuid::GenerateRandomV4().AsLowercaseString());
  account_profile.record_type_ = RecordType::kAccount;
  // Initial creator is unused for kLocalOrSyncable profiles.
  account_profile.initial_creator_id_ = kInitialCreatorChrome;
  return account_profile;
}

AutofillProfile AutofillProfile::ConvertToLocalOrSyncableProfile() const {
  DCHECK(record_type() != RecordType::kLocalOrSyncable);
  AutofillProfile local_or_syncable_profile = *this;
  // Since GUIDs are assumed to be unique across all profile record types, a new
  // GUID is assigned.
  local_or_syncable_profile.set_guid(
      base::Uuid::GenerateRandomV4().AsLowercaseString());
  local_or_syncable_profile.record_type_ = RecordType::kLocalOrSyncable;
  return local_or_syncable_profile;
}

FieldTypeSet AutofillProfile::FindInaccessibleProfileValues() const {
  FieldTypeSet inaccessible_fields;
  const std::string stored_country =
      base::UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
  // Consider only AddressFields which are invisible in the settings for some
  // countries.
  for (const AddressField& adress_field :
       {AddressField::ADMIN_AREA, AddressField::LOCALITY,
        AddressField::DEPENDENT_LOCALITY, AddressField::POSTAL_CODE,
        AddressField::SORTING_CODE}) {
    FieldType field_type = i18n::TypeForField(adress_field);
    CHECK_EQ(GroupTypeOfFieldType(field_type), FieldTypeGroup::kAddress);
    if (HasRawInfo(field_type) &&
        !GetAddress().IsAddressFieldSettingAccessible(field_type)) {
      inaccessible_fields.insert(field_type);
    }
  }
  return inaccessible_fields;
}

void AutofillProfile::ClearFields(const FieldTypeSet& fields) {
  for (FieldType field_type : fields) {
    SetRawInfoWithVerificationStatus(field_type, u"",
                                     VerificationStatus::kNoStatus);
  }
}

void AutofillProfile::MigrateRegularNameToPhoneticName() {
  name_.MigrateRegularNameToPhoneticName();
}

UsageHistoryInformation& AutofillProfile::usage_history() {
  return usage_history_information_;
}
const UsageHistoryInformation& AutofillProfile::usage_history() const {
  return usage_history_information_;
}

}  // namespace autofill

#if BUILDFLAG(IS_ANDROID)
DEFINE_JNI(AutofillProfile)
#endif
