// 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 "components/autofill/core/browser/filling/form_filler.h"

#include <stddef.h>

#include <algorithm>
#include <array>
#include <map>
#include <memory>
#include <optional>
#include <ranges>
#include <set>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>

#include "base/check.h"
#include "base/check_deref.h"
#include "base/check_op.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/map_util.h"
#include "base/containers/span.h"
#include "base/containers/to_vector.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/stack_allocated.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/types/expected.h"
#include "base/types/optional_ref.h"
#include "base/types/pass_key.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_trigger_source.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_ai/entity_type.h"
#include "components/autofill/core/browser/data_model/payments/credit_card.h"
#include "components/autofill/core/browser/data_quality/autofill_data_util.h"
#include "components/autofill/core/browser/field_type_utils.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/filling/addresses/field_filling_address_util.h"
#include "components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.h"
#include "components/autofill/core/browser/filling/field_filling_skip_reason.h"
#include "components/autofill/core/browser/filling/field_filling_util.h"
#include "components/autofill/core/browser/filling/filling_product.h"
#include "components/autofill/core/browser/filling/payments/field_filling_payments_util.h"
#include "components/autofill/core/browser/form_processing/autofill_ai/determine_attribute_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/foundations/autofill_client.h"
#include "components/autofill/core/browser/foundations/autofill_driver.h"
#include "components/autofill/core/browser/foundations/browser_autofill_manager.h"
#include "components/autofill/core/browser/integrators/one_time_tokens/otp_suggestion.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/metrics/form_interactions_ukm_logger.h"
#include "components/autofill/core/browser/metrics/log_event.h"
#include "components/autofill/core/browser/metrics/per_fill_metrics.h"
#include "components/autofill/core/browser/suggestions/suggestion_util.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/logging/log_buffer.h"
#include "components/autofill/core/common/logging/log_macros.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
#include "third_party/abseil-cpp/absl/functional/overload.h"
#include "third_party/libphonenumber/phonenumber_api.h"

namespace autofill {

namespace {

// Time to wait after a dynamic form change before triggering a refill.
// This is used for sites that change multiple things consecutively.
constexpr base::TimeDelta kWaitTimeForDynamicForms = base::Milliseconds(200);

FillDataType GetFillDataTypeFromFillingPayload(
    const FillingPayload& filling_payload) {
  return std::visit(
      absl::Overload{
          [](const AutofillProfile*) { return FillDataType::kAutofillProfile; },
          [](const CreditCard*) { return FillDataType::kCreditCard; },
          [](const EntityInstance*) { return FillDataType::kAutofillAi; },
          [](const VerifiedProfile*) { return FillDataType::kAutofillProfile; },
          [](const OtpFillData*) {
            return FillDataType::kOneTimePasswordValue;
          },
      },
      filling_payload);
}

// Returns how many fields with type |field_type| may be filled in a form at
// maximum.
size_t TypeValueFormFillingLimit(FieldType field_type) {
  switch (field_type) {
    case CREDIT_CARD_NUMBER:
      return kCreditCardTypeValueFormFillingLimit;
    case ADDRESS_HOME_STATE:
      return kStateTypeValueFormFillingLimit;
    default:
      return kTypeValueFormFillingLimit;
  }
}

std::string_view ActionPersistenceToString(
    mojom::ActionPersistence action_persistence) {
  switch (action_persistence) {
    case mojom::ActionPersistence::kFill:
      return "fill";
    case mojom::ActionPersistence::kPreview:
      return "preview";
  }
}

// Returns true iff `field` should be skipped during filling because its
// non-empty initial value is considered to be meaningful.
bool ShouldSkipFieldBecauseOfMeaningfulInitialValue(const AutofillField& field,
                                                    bool is_trigger_field) {
  // Assume that the trigger field can always be overwritten.
  if (is_trigger_field) {
    return false;
  }
  // Select (list) elements are currently not supported.
  if (field.IsSelectElement()) {
    return false;
  }
  // By default, empty initial values are not considered to be meaningful. A
  // value only consisting of whitespace is considered empty.
  if (base::TrimWhitespace(field.initial_value(), base::TrimPositions::TRIM_ALL)
          .empty()) {
    return false;
  }
  // Since this function is about analyzing the initial value, we should not
  // process fields that were modified, since those fields do not have their
  // initial values anymore.
  if (field.value() != field.initial_value() &&
      base::FeatureList::IsEnabled(
          features::kAutofillAllowFillingModifiedInitialValues)) {
    return false;
  }
  // If the field's initial value coincides with the value of its placeholder
  // attribute, don't consider the initial value to be meaningful.
  if (field.initial_value() == field.placeholder()) {
    return false;
  }

  // Pre-filled country calling codes (e.g., "+1" or "+49") may be overwritten.
  if (field.Type().GetGroups().contains(FieldTypeGroup::kPhone)) {
    int maybe_country_calling_code = 0;
    if (base::StringToInt(
            base::TrimWhitespace(field.value(), base::TrimPositions::TRIM_ALL),
            &maybe_country_calling_code)) {
      std::set<int> country_codes;
      ::i18n::phonenumbers::PhoneNumberUtil::GetInstance()
          ->GetSupportedCallingCodes(&country_codes);
      if (country_codes.contains(maybe_country_calling_code)) {
        return false;
      }
    }
  }

  // Fields that are non-empty on page load are not meant to be overwritten.
  //
  // At this point the field is known to contain a non-empty initial value at
  // page load.
  return true;
}

bool AllowPaymentSwapping(const AutofillField& trigger_field,
                          const AutofillField& field,
                          bool is_refill) {
  auto has_relevant_cc_field_type = [](const AutofillField& field) {
    const FieldType field_type = field.Type().GetCreditCardType();
    return field_type != UNKNOWN_TYPE &&
           field_type != CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
  };
  return field.last_modifier() == FieldModifier::kAutofill &&
         has_relevant_cc_field_type(trigger_field) &&
         has_relevant_cc_field_type(field) && !is_refill &&
         IsPaymentsFieldSwappingEnabled();
}

// Returns whether a filling action for `filling_product` should be included in
// the form autofill history.
bool ShouldRecordFillingHistory(FillingProduct filling_product) {
  switch (filling_product) {
    case FillingProduct::kAddress:
    case FillingProduct::kAutofillAi:
    case FillingProduct::kCreditCard:
    case FillingProduct::kLoyaltyCard:
    case FillingProduct::kOneTimePassword:
      return true;
    case FillingProduct::kNone:
    case FillingProduct::kMerchantPromoCode:
    case FillingProduct::kIban:
    case FillingProduct::kAutocomplete:
    case FillingProduct::kPasskey:
    case FillingProduct::kPassword:
    case FillingProduct::kCompose:
    case FillingProduct::kIdentityCredential:
    case FillingProduct::kDataList:
    case FillingProduct::kAtMemory:
      return false;
  }
  NOTREACHED();
}

// Called by `FormFiller::MaybeScheduleAutomaticRefill()` and constructs a
// refill value in case the website used JavaScript to reformat an expiration
// date like "05/2023" into "05 / 20" (i.e. it broke the year by cutting the
// last two digits instead of stripping the first two digits).
std::optional<FillingValueAndType> GetRefillValueForExpirationDate(
    const FormFieldData& field,
    const std::u16string& old_value) {
  // We currently support a single case of refilling credit card expiration
  // dates: If we filled the expiration date in a format "05/2023" and the
  // website turned it into "05 / 20" (i.e. it broke the year by cutting the
  // last two digits instead of stripping the first two digits).
  constexpr size_t kSupportedLength = std::string_view("MM/YYYY").size();
  if (old_value.length() != kSupportedLength) {
    return std::nullopt;
  }
  if (old_value == field.value()) {
    return std::nullopt;
  }
  if (field.IsSelectElement()) {
    return std::nullopt;
  }
  static constexpr char16_t kFormatRegEx[] =
      uR"(^(\d\d)(\s?[/-]?\s?)?(\d\d|\d\d\d\d)$)";
  std::vector<std::u16string> old_groups;
  if (!MatchesRegex<kFormatRegEx>(old_value, &old_groups)) {
    return std::nullopt;
  }
  DCHECK_EQ(old_groups.size(), 4u);

  std::vector<std::u16string> new_groups;
  if (!MatchesRegex<kFormatRegEx>(field.value(), &new_groups)) {
    return std::nullopt;
  }
  DCHECK_EQ(new_groups.size(), 4u);

  int old_month, old_year, new_month, new_year;
  if (!base::StringToInt(old_groups[1], &old_month) ||
      !base::StringToInt(old_groups[3], &old_year) ||
      !base::StringToInt(new_groups[1], &new_month) ||
      !base::StringToInt(new_groups[3], &new_year) ||
      old_groups[3].size() != 4 || new_groups[3].size() != 2 ||
      old_month != new_month ||
      // We need to refill if the first two digits of the year were preserved.
      old_year / 100 != new_year) {
    return std::nullopt;
  }
  std::u16string refill_value = field.value();
  CHECK(refill_value.size() >= 2);
  refill_value[refill_value.size() - 1] = '0' + (old_year % 10);
  refill_value[refill_value.size() - 2] = '0' + ((old_year % 100) / 10);
  return FillingValueAndType(refill_value, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
}

// During filling operations, each field gets assigned a set of
// `FieldFillingSkipReason` values, and only fields for which that set is empty
// are considered for filling, and the rest are skipped. This function returns
// reasons that can be ignored, which means that even if a field qualifies for
// it, it does not get added to the set.
DenseSet<FieldFillingSkipReason> GetIgnorableSkipReasons(
    AutofillTriggerSource trigger_source) {
  switch (trigger_source) {
    case AutofillTriggerSource::kGlic:
      // Note that `kUnrecognizedAutocompleteAttribute` is also governed by
      // AutofillField::ShouldSuppressSuggestionsAndFillingByDefault.
      return {FieldFillingSkipReason::kUnrecognizedAutocompleteAttribute,
              FieldFillingSkipReason::kUserFilledFields,
              FieldFillingSkipReason::kValuePrefilled};
    case AutofillTriggerSource::kNone:
    case AutofillTriggerSource::kPopup:
    case AutofillTriggerSource::kKeyboardAccessoryOrBottomSheet:
    case AutofillTriggerSource::kFormsSeen:
    case AutofillTriggerSource::kSelectOptionsChanged:
    case AutofillTriggerSource::kJavaScriptChangedAutofilledValue:
    case AutofillTriggerSource::kManualFallback:
    case AutofillTriggerSource::kDevtools:
    case AutofillTriggerSource::kScanCreditCard:
    case AutofillTriggerSource::kProactivePasswordRecovery:
    case AutofillTriggerSource::kCreditCardSaveAndFill:
    case AutofillTriggerSource::kProgrammaticRefill:
    case AutofillTriggerSource::kOmniboxAutofill:
      return {};
  }
  NOTREACHED();
}

}  // namespace

// Like FillingPayload, but may carry additional data needed for filling.
struct FormFiller::AugmentedFillingPayload {
  STACK_ALLOCATED();

 public:
  using EntityPayload = std::pair<const EntityInstance*,
                                  std::vector<AutofillFieldWithAttributeType>>;
  using Variant = std::variant<const AutofillProfile*,
                               const CreditCard*,
                               EntityPayload,
                               const VerifiedProfile*,
                               const OtpFillData*>;

  AugmentedFillingPayload(const FillingPayload& filling_payload,
                          FormStructure& form,
                          AutofillField& trigger_field)
      : variant(std::visit(
            absl::Overload{
                [](const AutofillProfile* autofill_profile) -> Variant {
                  return autofill_profile;
                },
                [](const CreditCard* credit_card) -> Variant {
                  return credit_card;
                },
                [&](const EntityInstance* entity) -> Variant {
                  return std::pair(entity,
                                   RationalizeAndDetermineAttributeTypes(
                                       form.fields(), trigger_field.section(),
                                       entity->type()));
                },
                [](const VerifiedProfile* verified_profile) -> Variant {
                  return verified_profile;
                },
                [](const OtpFillData* otp_filling_payload) -> Variant {
                  return otp_filling_payload;
                }},
            filling_payload)) {}

  FillingProduct filling_product() const {
    return std::visit(
        absl::Overload{
            [](const AutofillProfile*) { return FillingProduct::kAddress; },
            [](const CreditCard*) { return FillingProduct::kCreditCard; },
            [](const EntityPayload&) { return FillingProduct::kAutofillAi; },
            [](const VerifiedProfile*) {
              return FillingProduct::kIdentityCredential;
            },
            [](const OtpFillData*) {
              return FillingProduct::kOneTimePassword;
            }},
        variant);
  }

  bool supports_refills() const {
    switch (filling_product()) {
      case FillingProduct::kAddress:
      case FillingProduct::kCreditCard:
        return true;
      case FillingProduct::kAutocomplete:
      case FillingProduct::kAutofillAi:
      case FillingProduct::kCompose:
      case FillingProduct::kIban:
      case FillingProduct::kLoyaltyCard:
      case FillingProduct::kMerchantPromoCode:
      case FillingProduct::kIdentityCredential:
      case FillingProduct::kOneTimePassword:
      case FillingProduct::kAtMemory:
        return false;
      case FillingProduct::kPasskey:
      case FillingProduct::kPassword:
      case FillingProduct::kDataList:
      case FillingProduct::kNone:
        NOTREACHED();
    }
  }

  Variant variant;
};

// Keeps track of the filling context for a form, used to make refill
// attempts.
struct FormFiller::RefillContext {
  // |filling_payload| contains the data used to perform the initial filling
  // operation.
  RefillContext(const FillId& fill_id,
                FormData form,
                const AutofillField& field,
                const AugmentedFillingPayload& filling_payload,
                FieldTypeSet filled_types,
                base::flat_set<FieldGlobalId> blocked_fields)
      : fill_id(fill_id),
        filled_form(std::move(form)),
        filled_field_id(field.global_id()),
        filled_field_signature(field.GetFieldSignature()),
        filled_origin(field.origin()),
        original_fill_time(base::TimeTicks::Now()),
        types_originally_filled(std::move(filled_types)),
        blocked_fields(std::move(blocked_fields)),
        profile_or_credit_card(std::visit(
            absl::Overload{// Autofill with AI doesn't support refills.
                           [](const AugmentedFillingPayload::EntityPayload&)
                               -> std::variant<CreditCard, AutofillProfile> {
                             // Beware that `EntityPayload::second` holds
                             // raw_refs to AutofillFields. These references
                             // must not be stored in a RefillContext because
                             // they would dangle.
                             NOTREACHED();
                           },
                           // Verified Profiles doesn't support refills.
                           [](const VerifiedProfile*)
                               -> std::variant<CreditCard, AutofillProfile> {
                             NOTREACHED();
                           },
                           // OTP filling doesn't support refills.
                           [](const OtpFillData*)
                               -> std::variant<CreditCard, AutofillProfile> {
                             NOTREACHED();
                           },
                           [](const auto* x) {
                             return std::variant<CreditCard, AutofillProfile>(
                                 *x);
                           }},
            filling_payload.variant)) {}

  ~RefillContext() = default;

  // Uniquely identifies the initial fill operation.
  const FillId fill_id;
  // The form filled in the first attempt for filling. Used to check whether
  // a refill should be attempted upon parsing an updated FormData.
  const FormData filled_form;
  // Possible identifiers of the field that was focused when the form was
  // initially filled. A refill shall be triggered from the same field.
  const FieldGlobalId filled_field_id;
  const FieldSignature filled_field_signature;
  // The security origin from which the field was filled.
  const url::Origin filled_origin;
  // The time at which the initial fill occurred.
  // TODO(crbug.com/41490871): Remove in favor of
  // FormStructure::last_filling_timestamp_.
  const base::TimeTicks original_fill_time;
  // Whether refills caused by DOM changes are allowed.
  bool allows_automatic_refill = true;
  // The timer used to trigger a refill.
  base::OneShotTimer on_refill_timer;
  // The field types that were initially filled.
  const FieldTypeSet types_originally_filled;
  // If populated, this map determines which values will be filled into a
  // field (it does not matter whether the field already contains a value).
  std::map<FieldGlobalId, FillingValueAndType> forced_fill_values;
  // Fields that should not be re-filled because another filling operation or
  // product of higher priority claims them.
  //
  // TODO(crbug.com/489280538): There are cases where the set of FieldGlobalIds
  // can change between original fill and refill, for example if a field has
  // been added to the form. A refill will currently fail to block those fields
  // even if it should.
  const base::flat_set<FieldGlobalId> blocked_fields;
  // The profile or credit card that was used for the initial fill. This is
  // slightly different from `filling_payload` that is used by the filling
  // function: This contains actual objects because this needs to survive
  // potential storage mutation, and this only contains payloads that support
  // refills.
  const std::variant<CreditCard, AutofillProfile> profile_or_credit_card;
};

FormFiller::RefillOptions::RefillOptions() = default;

FormFiller::RefillOptions FormFiller::RefillOptions::NotRefill() {
  return {};
}

FormFiller::RefillOptions FormFiller::RefillOptions::Refill(
    FieldTypeSet originally_filled,
    RefillTriggerReason reason) {
  RefillOptions r;
  r.originally_filled_ = std::move(originally_filled);
  r.reason_ = reason;
  return r;
}

bool FormFiller::RefillOptions::is_refill() const {
  return originally_filled_.has_value();
}

bool FormFiller::RefillOptions::may_refill(
    const FieldTypeSet& field_types) const {
  CHECK(is_refill());
  FieldTypeGroupSet requested_groups(field_types, &GroupTypeOfFieldType);
  FieldTypeGroupSet filled_groups(*originally_filled_, &GroupTypeOfFieldType);
  if (!filled_groups.contains_all(requested_groups)) {
    return false;
  }

  // Rule for CCs: Filling other CC information without Credit Card Number or
  // CVC does not allow refilling CCN/CVC.
  if (requested_groups.contains(FieldTypeGroup::kCreditCard) ||
      requested_groups.contains(FieldTypeGroup::kStandaloneCvcField)) {
    auto contains_sensitive_cc = [](const FieldTypeSet& types) {
      return types.contains_any({CREDIT_CARD_NUMBER,
                                 CREDIT_CARD_VERIFICATION_CODE,
                                 CREDIT_CARD_STANDALONE_VERIFICATION_CODE});
    };
    return contains_sensitive_cc(*originally_filled_) ||
           !contains_sensitive_cc(field_types);
  }

  return true;
}

DenseSet<FieldFillingSkipReason> FormFiller::GetFillingSkipReasonsForField(
    const AutofillField& field,
    const AutofillField& trigger_field,
    const RefillOptions& refill_options,
    base::flat_map<FieldType, size_t>& type_count,
    const base::flat_set<FieldGlobalId>& blocked_fields,
    AutofillTriggerSource trigger_source,
    AutocompleteUnrecognizedBehavior ac_unrecognized_behavior) {
  DenseSet<FieldFillingSkipReason> skip_reasons;
  const bool is_trigger_field = field.global_id() == trigger_field.global_id();

  auto add_if = [&skip_reasons,
                 ignorable_reasons = GetIgnorableSkipReasons(trigger_source)](
                    bool condition, FieldFillingSkipReason reason) {
    if (condition && !ignorable_reasons.contains(reason)) {
      skip_reasons.insert(reason);
    }
  };

  // Do not fill fields that are not part of the filled section, as this has
  // higher probability to be inaccurate (a second full name field probably
  // exists not to be filled with the same info as the first full name field).
  add_if(field.section() != trigger_field.section(),
         FieldFillingSkipReason::kNotInFilledSection);

  // Some fields are rationalized so that they are only filled when focuses
  // (since we allow for example multiple phone number fields to exist in the
  // same section). Therefore we skip those fields if they're not focused.
  add_if(field.only_fill_when_focused() && !is_trigger_field,
         FieldFillingSkipReason::kNotFocused);

  // An address fields with unrecognized autocomplete attribute is only filled
  // when it is the field triggering the filling operation.
  add_if(
      !is_trigger_field && field.ShouldSuppressSuggestionsAndFillingByDefault(
                               ac_unrecognized_behavior),
      FieldFillingSkipReason::kUnrecognizedAutocompleteAttribute);

  // Don't fill unfocusable fields, with the exception of <select> fields, for
  // the sake of filling the synthetic fields.
  add_if(!field.is_focusable() && !field.IsSelectElement(),
         FieldFillingSkipReason::kInvisibleField);

  // Do not fill fields that have been edited by the user, except if the field
  // is empty and its initial value (= cached value) was empty as well. A
  // similar check is done in ForEachMatchingFormFieldCommon(), which
  // frequently has false negatives.
  add_if((field.properties_mask() & kUserTyped) &&
             !(field.value().empty() && field.initial_value().empty()) &&
             !is_trigger_field,
         FieldFillingSkipReason::kUserFilledFields);

  // Don't fill previously autofilled fields except the initiating field or
  // when it's a refill or for credit card fields, when
  // `kAutofillPaymentsFieldSwapping` is enabled.
  //
  // Also exclude the case of empty fields, because sometimes autofilled fields
  // can be cleared without the modifiers being reset (e.g. if the form is reset
  // by JS).
  add_if(field.last_modifier() == FieldModifier::kAutofill &&
             !field.value().empty() && !is_trigger_field &&
             !refill_options.is_refill() &&
             !AllowPaymentSwapping(trigger_field, field,
                                   refill_options.is_refill()),
         FieldFillingSkipReason::kAlreadyAutofilled);

  AutofillType autofill_type = field.Type();
  FieldTypeSet field_types = autofill_type.GetTypes();

  // On a refill, only fill fields from type groups that were present during
  // the initial fill.
  add_if(refill_options.is_refill() && !refill_options.may_refill(field_types),
         FieldFillingSkipReason::kRefillNotInInitialFill);

  // A field with a specific type is only allowed to be filled a limited
  // number of times given by |TypeValueFormFillingLimit(field_type)|.
  for (FieldType field_type : field_types) {
    add_if(++type_count[field_type] > TypeValueFormFillingLimit(field_type),
           FieldFillingSkipReason::kFillingLimitReachedType);
  }

  // Don't fill meaningfully pre-filled fields but overwrite placeholders.
  add_if(
      ShouldSkipFieldBecauseOfMeaningfulInitialValue(field, is_trigger_field),
      FieldFillingSkipReason::kValuePrefilled);

  // Do not fill fields that are blocked by another filling operation or
  // product.
  add_if(blocked_fields.contains(field.global_id()),
         FieldFillingSkipReason::kBlockedByOtherFillingOperationOrProduct);

  return skip_reasons;
}

FormFiller::FormFiller(BrowserAutofillManager& manager) : manager_(manager) {}

FormFiller::~FormFiller() = default;

LogManager* FormFiller::log_manager() {
  return manager_->client().GetCurrentLogManager();
}

void FormFiller::Reset() {
  refill_context_.clear();
  form_autofill_history_.Reset();
}

// static
base::flat_map<FieldGlobalId, DenseSet<FieldFillingSkipReason>>
FormFiller::GetFieldFillingSkipReasons(
    const FormStructure& form,
    const AutofillField& trigger_field,
    const RefillOptions& refill_options,
    FillingProduct filling_product,
    AutofillTriggerSource trigger_source,
    const AutofillClient& client,
    base::flat_set<FieldGlobalId> blocked_fields) {
  // Counts the number of times a type was seen in the section to be filled.
  // This is used to limit the maximum number of fills per value.
  base::flat_map<FieldType, size_t> type_count;
  type_count.reserve(form.fields().size());

  if (filling_product == FillingProduct::kAddress) {
    blocked_fields.insert_range(GetFieldsFillableByAutofillAi(form, client));
  }

  auto skip_reasons =
      base::MakeFlatMap<FieldGlobalId, DenseSet<FieldFillingSkipReason>>(
          form, {}, [](const std::unique_ptr<AutofillField>& field) {
            return std::make_pair(field->global_id(),
                                  DenseSet<FieldFillingSkipReason>{});
          });
  for (const std::unique_ptr<AutofillField>& field : form.fields()) {
    // Log events when the fields on the form are filled by autofill
    // suggestion.
    DenseSet<FieldFillingSkipReason> field_skip_reasons =
        GetFillingSkipReasonsForField(
            *field, trigger_field, refill_options, type_count, blocked_fields,
            trigger_source, GetAcUnrecognizedBehavior(client));

    // Usually, `skip_reasons[field_id].empty()` before executing the line
    // below. It may not be the case though because FieldGlobalIds may not be
    // unique among `FormData::fields_` (see crbug.com/41496988), so a previous
    // iteration may have added skip reasons for `field_id`. To err on the side
    // of caution we accumulate all skip reasons found in any iteration.
    skip_reasons[field->global_id()].insert_all(field_skip_reasons);
  }
  return skip_reasons;
}

base::flat_map<FieldGlobalId, DenseSet<FieldFillingSkipReason>>
FormFiller::GetFieldFillingSkipReasons(
    const FormStructure& form,
    const AutofillField& trigger_field,
    const RefillOptions& refill_options,
    FillingProduct filling_product,
    AutofillTriggerSource trigger_source,
    const AutofillClient& client,
    base::flat_set<FieldGlobalId> blocked_fields,
    const base::flat_map<FieldGlobalId,
                         base::expected<ValueAndTypeAndOverride, std::string>>&
        filling_content) {
  base::flat_map<FieldGlobalId, DenseSet<FieldFillingSkipReason>> skip_reasons =
      GetFieldFillingSkipReasons(form, trigger_field, refill_options,
                                 filling_product, trigger_source, client,
                                 std::move(blocked_fields));

  for (const std::unique_ptr<AutofillField>& field : form.fields()) {
    const base::expected<ValueAndTypeAndOverride, std::string>
        expected_content = filling_content.at(field->global_id());

    // Denotes whether an autofilled field is eligible for filling (no prior
    // `FieldFillingSkipReasons`), a value to fill is found by
    // `GetFieldFillingData()`, but that value is the same as the one already
    // autofilled in the field.
    const bool autofilled_value_did_not_change =
        expected_content.has_value() &&
        field->is_autofilled_according_to_renderer() &&
        field->value() == expected_content->value &&
        field->selected_option_text() == expected_content->select_text;

    if (!expected_content.has_value()) {
      skip_reasons[field->global_id()].insert(
          FieldFillingSkipReason::kNoValueToFill);
    }
    if (autofilled_value_did_not_change) {
      skip_reasons[field->global_id()].insert(
          FieldFillingSkipReason::kAutofilledValueDidNotChange);
    }
    if (expected_content.has_value() &&
        !manager_->driver().IsSafeToFill(
            *field, expected_content->filling_type,
            client.GetLastCommittedPrimaryMainFrameOrigin(),
            trigger_field.origin())) {
      skip_reasons[field->global_id()].insert(
          FieldFillingSkipReason::kIframeSecurityPolicy);
    }
  }
  return skip_reasons;
}

void FormFiller::UndoAutofill(mojom::ActionPersistence action_persistence,
                              FormStructure& form,
                              const FieldGlobalId& trigger_field_id,
                              FillingProduct filling_product) {
  if (!form_autofill_history_.HasHistory(trigger_field_id)) {
    LOG_AF(log_manager())
        << "Could not undo the filling operation on field " << trigger_field_id
        << " because history was dropped upon reaching history limit of "
        << kMaxStorableFieldFillHistory;
    return;
  }

  const auto fill_operation_it =
      form_autofill_history_.GetLastFormFillingEntryForField(trigger_field_id);

  std::vector<FormFieldData> result_fields = base::ToVector(
      form.fields(), [](const std::unique_ptr<AutofillField>& field) {
        return FormFieldData(*field);
      });
  base::flat_map<FieldGlobalId, AutofillField*> cached_fields =
      base::MakeFlatMap<FieldGlobalId, AutofillField*>(
          form.fields(), {}, [](const std::unique_ptr<AutofillField>& field) {
            return std::make_pair(field->global_id(), field.get());
          });

  // Remove the fields to be skipped so that we only pass fields to be modified
  // by the renderer.
  std::erase_if(result_fields, [&](const FormFieldData& field) {
    const auto field_fill_operation_it =
        form_autofill_history_.GetLastFormFillingEntryForField(
            field.global_id());
    return
        // Skip fields whose last autofill operation is different
        // than the one of the trigger field.
        field_fill_operation_it != fill_operation_it ||
        // Skip not-autofilled fields as undo only acts on autofilled
        // fields. Only exception is the fields that were emptied due to
        // suggestion swapping.
        // Note that `field_fill_operation` is guaranteed to have an entry for
        // `field.global_id()` because of the condition right above.
        // TODO(crbug.com/393114125): Change to use
        // `AutofillField::field_modifiers_`.
        (!field.is_autofilled_according_to_renderer() &&
         !field.value().empty() &&
         field_fill_operation_it->at(field.global_id()).ignore_is_autofilled) ||
        // Skip fields that are not cached to avoid unexpected outcomes.
        !cached_fields.contains(field.global_id()) ||
        // Skip fields which have a different filling product than the trigger
        // field. This is to avoid modifying a field that was autofilled later
        // with a filling product that doesn't support Undo (e.g.,
        // Autocomplete).
        cached_fields[field.global_id()]->filling_product() != filling_product;
  });

  for (FormFieldData& field : result_fields) {
    AutofillField& autofill_field =
        CHECK_DEREF(cached_fields[field.global_id()]);
    auto it = fill_operation_it->find(field.global_id());
    // See comments in the `erase_if` block for why this is guaranteed.
    CHECK(it != fill_operation_it->end());
    const FormAutofillHistory::FieldFillingEntry& previous_state = it->second;

    // Update the FormFieldData to be sent for the renderer.
    field.set_value(previous_state.value);

    // This is an abuse of naming. `is_autofilled_according_to_renderer` is
    // being set here so that the form is sent to the renderer and the renderer
    // is able to fill them and update the background accordingly.
    field.set_is_autofilled_according_to_renderer(
        previous_state.is_autofilled_according_to_renderer);

    // Update the cached AutofillField in the browser if the operation isn't a
    // preview.
    if (action_persistence == mojom::ActionPersistence::kFill) {
      autofill_field.set_field_modifiers(previous_state.field_modifiers,
                                         /*pass_key=*/{});
      autofill_field.set_autofill_source_profile_guid(
          previous_state.autofill_source_profile_guid);
      autofill_field.set_autofilled_type(previous_state.autofilled_type);
      autofill_field.set_filling_product(previous_state.filling_product);
    }
  }

  if (action_persistence == mojom::ActionPersistence::kFill) {
    // The filling history is not cleared on previews as it might be used for
    // future previews or for the filling. It is also cleared field by field
    // because some fields in the current entry might not be used now but
    // could still be valuable (see crbug.com/416019464).
    form_autofill_history_.EraseFieldFillingEntries(
        fill_operation_it,
        base::ToVector(result_fields, &FormFieldData::global_id));
  }

  // Do not attempt a refill after an Undo operation.
  if (GetRefillContext(form.global_id())) {
    SetRefillContext(form.global_id(), nullptr);
  }

  // Since Undo only affects fields that were already filled, and only sets
  // values to fields to something that already existed in it prior to the
  // filling, it is okay to bypass the filling security checks and hence passing
  // dummy values for `triggered_origin` and `field_type_map`.
  manager_->driver().ApplyFormAction(
      mojom::FormActionType::kUndo, action_persistence, result_fields,
      FillId::Create(), /*supports_refill=*/false, url::Origin(),
      /*field_type_map=*/{});
}

void FormFiller::FillOrPreviewField(mojom::ActionPersistence action_persistence,
                                    mojom::FieldActionType action_type,
                                    const FieldGlobalId& field_id,
                                    AutofillField* field,
                                    const std::u16string& value,
                                    FillingProduct filling_product,
                                    std::optional<FieldType> field_type_used) {
  CHECK(!field || field->global_id() == field_id);
  if (field && action_persistence == mojom::ActionPersistence::kFill) {
    if (ShouldRecordFillingHistory(filling_product)) {
      form_autofill_history_.AddFormFillingEntry(
          std::to_array<const AutofillField*>({field}), filling_product,
          /*is_refill=*/false);
    }
    field->AddFieldModifier(FieldModifier::kAutofill);
    field->set_autofilled_type(field_type_used);
    field->set_filling_product(filling_product);
    field->AppendLogEventIfNotRepeated(FillFieldLogEvent{
        .fill_event_id = GetNextFillEventId(),
        .had_value_before_filling = ToOptionalBoolean(!field->value().empty()),
        .autofill_skipped_status = FieldFillingSkipReason::kNotSkipped,
        .was_autofilled_before_security_policy = ToOptionalBoolean(true),
        .had_value_after_filling = ToOptionalBoolean(true)});
  }
  manager_->driver().ApplyFieldAction(action_type, action_persistence, field_id,
                                      value);
  manager_->OnDidFillOrPreviewField(action_persistence, field_type_used);
}

void FormFiller::FillOrPreviewForm(
    mojom::ActionPersistence action_persistence,
    const FillingPayload& filling_payload,
    FormStructure& form,
    AutofillField& trigger_field,
    AutofillTriggerSource trigger_source,
    const base::flat_set<FieldGlobalId>& blocked_fields,
    FillId fill_id,
    const std::map<FieldGlobalId, FillingValueAndType>& forced_fill_values,
    RefillOptions refill_options) {
  const AugmentedFillingPayload augmented_filling_payload =
      AugmentedFillingPayload(filling_payload, form, trigger_field);

  const auto filling_content =
      base::MakeFlatMap<FieldGlobalId,
                        base::expected<ValueAndTypeAndOverride, std::string>>(
          form.fields(), {}, [&](const std::unique_ptr<AutofillField>& field) {
            using Pair =
                std::pair<const FieldGlobalId,
                          base::expected<ValueAndTypeAndOverride, std::string>>;

            std::string failure_to_fill;
            if (std::optional<ValueAndTypeAndOverride> filling_content =
                    GetFieldFillingData(
                        *field, augmented_filling_payload, forced_fill_values,
                        action_persistence,
                        AllowPaymentSwapping(trigger_field, *field,
                                             refill_options.is_refill()),
                        &failure_to_fill)) {
              return Pair(field->global_id(), std::move(*filling_content));
            }
            return Pair(field->global_id(), base::unexpected(failure_to_fill));
          });

  base::flat_map<FieldGlobalId, DenseSet<FieldFillingSkipReason>> skip_reasons =
      GetFieldFillingSkipReasons(form, trigger_field, refill_options,
                                 augmented_filling_payload.filling_product(),
                                 trigger_source, manager_->client(),
                                 blocked_fields, filling_content);

  // These are the fields that will be sent to the renderer so that the
  // corresponding `blink::WebFormControlElement`s can be filled.
  std::vector<FormFieldData> result_fields = base::ToVector(
      form.fields(), [](const std::unique_ptr<AutofillField>& field) {
        return FormFieldData(*field);
      });
  absl::flat_hash_map<FieldGlobalId, FieldType> filled_field_types;

  for (auto [result_field, field] :
       std::views::zip(result_fields, form.fields())) {
    if (!skip_reasons[field->global_id()].empty()) {
      continue;
    }

    const base::expected<ValueAndTypeAndOverride, std::string>&
        expected_content = filling_content.at(field->global_id());
    CHECK(expected_content.has_value());

    FillField(expected_content.value(), result_field, action_persistence,
              trigger_source,
              AllowPaymentSwapping(trigger_field, *field,
                                   refill_options.is_refill()));
    filled_field_types.emplace(field->global_id(),
                               expected_content->filling_type);
  }

  const bool may_refill_in_future = MaybeInitializeRefillContext(
      action_persistence, form, trigger_field, augmented_filling_payload,
      blocked_fields, fill_id, result_fields, filled_field_types,
      refill_options);

  // Fields with at least one skip reason must not be filled.
  std::erase_if(result_fields, [&skip_reasons](const FormFieldData& field) {
    return !skip_reasons[field.global_id()].empty();
  });
  base::flat_set<FieldGlobalId> safe_filled_field_ids =
      manager_->driver().ApplyFormAction(
          mojom::FormActionType::kFill, action_persistence, result_fields,
          fill_id, /*supports_refill=*/may_refill_in_future,
          trigger_field.origin(), filled_field_types);

  // This will hold the cached version of `result_fields`.
  std::vector<const AutofillField*> safe_filled_fields =
      base::ToVector(safe_filled_field_ids,
                     [&](FieldGlobalId field_id) -> const AutofillField* {
                       return form.GetFieldById(field_id);
                     });

  if (action_persistence == mojom::ActionPersistence::kFill) {
    form.set_last_filling_timestamp(base::TimeTicks::Now());

    AppendFillLogEvents(form, trigger_field, safe_filled_field_ids,
                        skip_reasons, filling_payload,
                        refill_options.is_refill());

    // Save filling history to support undoing it later if needed.
    if (ShouldRecordFillingHistory(
            augmented_filling_payload.filling_product())) {
      form_autofill_history_.AddFormFillingEntry(
          safe_filled_fields, augmented_filling_payload.filling_product(),
          refill_options.is_refill());
    }

    // If the operation was a persistent fill and not a preview, update the
    // cache with the information changed during the fill operation.
    UpdateCacheOnFill(form, result_fields, safe_filled_field_ids,
                      filled_field_types, augmented_filling_payload);
  }

  LogFillingInternal(action_persistence, form, refill_options,
                     augmented_filling_payload.filling_product(),
                     filling_content, skip_reasons);

  // TODO(crbug.com/40227071): Remove.
  base::flat_set<FieldGlobalId> filled_field_ids;
  for (const auto& [id, reasons] : skip_reasons) {
    if (reasons.empty() ||
        reasons == DenseSet{FieldFillingSkipReason::kIframeSecurityPolicy}) {
      filled_field_ids.insert(id);
    }
  }

  manager_->OnDidFillOrPreviewForm(
      action_persistence, form, trigger_field, safe_filled_fields,
      std::move(filled_field_ids), skip_reasons, filling_payload,
      trigger_source, refill_options.reason());
}

void FormFiller::SuppressAutomaticRefills(const FillId& fill_id) {
  RefillContext* refill_context = GetRefillContext(fill_id);
  if (!refill_context) {
    return;
  }
  refill_context->on_refill_timer.Stop();
  refill_context->allows_automatic_refill = false;
}

void FormFiller::MaybeScheduleProgrammaticRefill(const FillId& fill_id) {
  RefillContext* refill_context = GetRefillContext(fill_id);
  if (!refill_context) {
    return;
  }

  if (base::TimeDelta delta =
          base::TimeTicks::Now() - refill_context->original_fill_time;
      delta > limit_before_programmatic_refill_) {
    return;
  }

  // If a timer for the refill was already running, it means another
  // RequestRefill() message arrived, perhaps from another frame. In that case,
  // we restart the timer.
  refill_context->on_refill_timer.Start(
      FROM_HERE, kWaitTimeForDynamicForms,
      base::BindRepeating(
          [](base::WeakPtr<FormFiller> self, const FormGlobalId& form_id) {
            if (!self) {
              return;
            }
            // Taking the form from the cache is not entirely correct until the
            // AutofillField::is_autofilled() semantics is fixed:
            // crbug.com/393114125.
            // TODO(crbug.com/466333215): Make sure crbug.com/393114125 is fixed
            // before programmatic refills move beyond prototyping.
            const FormStructure* form =
                self->manager_->FindCachedFormById(form_id);
            if (!form) {
              return;
            }
            self->TriggerRefill(form->global_id(),
                                AutofillTriggerSource::kProgrammaticRefill,
                                RefillTriggerReason::kProgrammaticRefill);
          },
          weak_ptr_factory_.GetWeakPtr(),
          refill_context->filled_form.global_id()));
}

void FormFiller::MaybeScheduleAutomaticRefill(
    const FormStructure& form,
    RefillTriggerReason refill_trigger_reason,
    AutofillTriggerSource trigger_source,
    base::optional_ref<const AutofillField> field,
    base::optional_ref<const std::u16string> old_value) {
  CHECK_NE(refill_trigger_reason, RefillTriggerReason::kProgrammaticRefill);

  // Should not refill if a form with the same FormGlobalId has not been filled
  // before or if it has been refilled before.
  RefillContext* refill_context = GetRefillContext(form.global_id());
  if (!refill_context || !refill_context->allows_automatic_refill) {
    return;
  }

  // Should not refill a form that has been filled a long time ago as the UX
  // would appear strange.
  // TODO(crbug.com/41490871): Use `FormStructure::last_filling_timestamp_`
  // instead of `RefillContext::original_fill_time`.
  if (base::TimeDelta delta =
          base::TimeTicks::Now() - refill_context->original_fill_time;
      delta > limit_before_automatic_refill_) {
    return;
  }

  switch (refill_trigger_reason) {
    case RefillTriggerReason::kFormChanged:
      // Only refill if the form actually changed since it was filled.
      // Since we won't schedule another refill, we should be cautious not to
      // prematurely schedule refills.
      // TODO(crbug.com/459458715): Compare overall types directly and get rid
      // of the field attributes comparison.
      if (std::ranges::equal(
              refill_context->filled_form.fields(), form.fields(),
              [](const FormFieldData& f,
                 const std::unique_ptr<AutofillField>& g) {
                return FormFieldData::IdenticalAndEquivalentDomElements(
                    f, *g,
                    DenseSet<FormFieldData::Exclusion>{
                        FormFieldData::Exclusion::kNotRefillRelated});
              })) {
        return;
      }
      break;
    case RefillTriggerReason::kSelectOptionsChanged:
      if (!field || !field->IsSelectElement() ||
          field->Type().GetGroups().contains_none(
              FieldTypeGroupSet(refill_context->types_originally_filled,
                                &GroupTypeOfFieldType))) {
        // The element in question is not fillable as a result of this signal.
        // Do not trigger a refill as it would most likely be a trivial one.
        return;
      }
      break;
    case RefillTriggerReason::kExpirationDateFormatted:
      CHECK(field && old_value);
      if (std::optional<FillingValueAndType> refill_value =
              GetRefillValueForExpirationDate(*field, *old_value)) {
        refill_context->forced_fill_values[field->global_id()] =
            *std::move(refill_value);
        break;
      }
      return;
    case RefillTriggerReason::kProgrammaticRefill:
      NOTREACHED();
  }
  ScheduleRefill(form.global_id(), CHECK_DEREF(refill_context), trigger_source,
                 refill_trigger_reason);
}

void FormFiller::ScheduleRefill(const FormGlobalId& form_id,
                                RefillContext& refill_context,
                                AutofillTriggerSource trigger_source,
                                RefillTriggerReason refill_trigger_reason) {
  // If a timer for the refill was already running, it means the form
  // changed again. In that case, we restart the timer.
  refill_context.on_refill_timer.Start(
      FROM_HERE, kWaitTimeForDynamicForms,
      base::BindRepeating(&FormFiller::TriggerRefill,
                          weak_ptr_factory_.GetWeakPtr(), form_id,
                          trigger_source, refill_trigger_reason));
}

void FormFiller::TriggerRefill(const FormGlobalId& form_id,
                               AutofillTriggerSource trigger_source,
                               RefillTriggerReason refill_trigger_reason) {
  FormStructure* form = manager_->FindCachedFormById(form_id, /*pass_key=*/{});
  if (!form) {
    return;
  }
  RefillContext* refill_context = GetRefillContext(form->global_id());
  if (!refill_context) {
    // The refill attempt can happen from different paths, some of which happen
    // after waiting for a while. Therefore, although this condition has been
    // checked prior to calling TriggerRefill, it may not hold, when we get
    // here.
    return;
  }

  // Try to find the field from which the original fill originated.
  // The precedence for the look up is the following:
  //  - focusable `filled_field_id`
  //  - focusable `filled_field_signature`
  //  - non-focusable `filled_field_id`
  //  - non-focusable `filled_field_signature`
  // and prefer newer renderer ids.
  auto comparison_attributes =
      [&](const std::unique_ptr<AutofillField>& field) {
        return std::make_tuple(
            field->origin() == refill_context->filled_origin,
            field->is_focusable(),
            field->global_id() == refill_context->filled_field_id,
            field->GetFieldSignature() ==
                refill_context->filled_field_signature,
            field->renderer_id());
      };
  auto it = std::ranges::max_element(*form, {}, comparison_attributes);
  AutofillField* trigger_field = it != form->end() ? it->get() : nullptr;
  bool found_matching_element =
      trigger_field &&
      trigger_field->origin() == refill_context->filled_origin &&
      (trigger_field->global_id() == refill_context->filled_field_id ||
       trigger_field->GetFieldSignature() ==
           refill_context->filled_field_signature);
  if (!found_matching_element) {
    return;
  }

  autofill_metrics::LogRefillTriggerReason(refill_trigger_reason);

  std::visit(
      [&](const auto& profile_or_credit_card) {
        FillOrPreviewForm(
            mojom::ActionPersistence::kFill, &profile_or_credit_card, *form,
            *trigger_field, trigger_source, refill_context->blocked_fields,
            refill_context->fill_id, refill_context->forced_fill_values,
            RefillOptions::Refill(refill_context->types_originally_filled,
                                  refill_trigger_reason));
      },
      refill_context->profile_or_credit_card);

  // TODO(crbug.com/459458715): Consider only clearing the `RefillContext` after
  // making sure that the refill will fill at least one field.
  SetRefillContext(form->global_id(), nullptr);
}

void FormFiller::SetRefillContext(FormGlobalId form_id,
                                  std::unique_ptr<RefillContext> context) {
  if (context) {
    refill_context_.insert_or_assign(form_id, std::move(context));
  } else {
    refill_context_.erase(form_id);
  }
}

FormFiller::RefillContext* FormFiller::GetRefillContext(FormGlobalId form_id) {
  auto it = refill_context_.find(form_id);
  return it != refill_context_.end() ? it->second.get() : nullptr;
}

FormFiller::RefillContext* FormFiller::GetRefillContext(const FillId& fill_id) {
  auto it = std::ranges::find_if(refill_context_, [&](const auto& p) {
    return p.second && p.second->fill_id == fill_id;
  });
  return it != refill_context_.end() ? it->second.get() : nullptr;
}

bool FormFiller::MaybeInitializeRefillContext(
    mojom::ActionPersistence action_persistence,
    const FormStructure& form,
    const AutofillField& autofill_trigger_field,
    const AugmentedFillingPayload& augmented_filling_payload,
    const base::flat_set<FieldGlobalId>& blocked_fields,
    FillId fill_id,
    const std::vector<FormFieldData>& result_fields,
    const absl::flat_hash_map<FieldGlobalId, FieldType>& filled_field_types,
    RefillOptions refill_options) {
  if (action_persistence != mojom::ActionPersistence::kFill ||
      !augmented_filling_payload.supports_refills() ||
      refill_options.is_refill()) {
    return false;
  }

  FormData refill_form = form.ToFormData();
  refill_form.set_fields(std::move(result_fields));

  SetRefillContext(
      form.global_id(),
      std::make_unique<RefillContext>(
          fill_id, std::move(refill_form), autofill_trigger_field,
          augmented_filling_payload,
          FieldTypeSet(filled_field_types,
                       &std::pair<const FieldGlobalId, FieldType>::second),
          blocked_fields));

  return true;
}

std::optional<FormFiller::ValueAndTypeAndOverride>
FormFiller::GetFieldFillingData(
    const AutofillField& field,
    const AugmentedFillingPayload& filling_payload,
    const std::map<FieldGlobalId, FillingValueAndType>& forced_fill_values,
    mojom::ActionPersistence action_persistence,
    bool allow_suggestion_swapping,
    std::string* failure_to_fill) {
  if (auto it = forced_fill_values.find(field.global_id());
      it != forced_fill_values.end()) {
    return ValueAndTypeAndOverride{it->second, /*value_is_an_override=*/true};
  }
  FillingValueAndType filling_value_and_type = std::visit(
      absl::Overload{
          [&](const AutofillProfile* profile) {
            return GetFillingValueAndTypeForProfile(
                CHECK_DEREF(profile), manager_->client().GetAppLocale(),
                field.Type(), field, manager_->client().GetAddressNormalizer(),
                failure_to_fill);
          },
          [&](const CreditCard* credit_card) {
            return GetFillingValueAndTypeForCreditCard(
                CHECK_DEREF(credit_card), manager_->client().GetAppLocale(),
                action_persistence, field,
                manager_->client().IsCvcSavingSupported(), failure_to_fill);
          },
          [&](const AugmentedFillingPayload::EntityPayload&
                  entity_and_fields_and_types) {
            const EntityInstance& entity =
                CHECK_DEREF(entity_and_fields_and_types.first);
            const std::vector<AutofillFieldWithAttributeType>& fields =
                entity_and_fields_and_types.second;
            return GetFillingValueAndTypeForEntity(
                entity, fields, field, action_persistence,
                manager_->client().GetAppLocale(),
                manager_->client().GetAddressNormalizer());
          },
          [&](const VerifiedProfile* profile) {
            const FieldType field_type =
                field.Type().GetIdentityCredentialType();
            auto it = profile->find(field_type);
            std::u16string value = it == profile->end() ? u"" : it->second;
            return FillingValueAndType(value, field_type);
          },
          [&](const OtpFillData* otp_fill_data) {
            auto it = otp_fill_data->find(field.global_id());
            const std::u16string& value =
                it == otp_fill_data->end() ? u"" : it->second;
            return FillingValueAndType(value,
                                       field.Type().GetPasswordManagerType());
          }},
      filling_payload.variant);

  if (filling_value_and_type.value.empty() && !allow_suggestion_swapping) {
    if (failure_to_fill) {
      *failure_to_fill += "No value to fill available. ";
    }
    return std::nullopt;
  }
  return ValueAndTypeAndOverride{filling_value_and_type,
                                 /*value_is_an_override=*/false};
}

void FormFiller::FillField(const ValueAndTypeAndOverride& filling_content,
                           FormFieldData& field_data,
                           mojom::ActionPersistence action_persistence,
                           AutofillTriggerSource trigger_source,
                           bool allow_suggestion_swapping) {
  field_data.set_value(filling_content.value);
  field_data.set_force_override(filling_content.value_is_an_override ||
                                allow_suggestion_swapping);
  if (field_data.IsSelectElement() && filling_content.select_text) {
    field_data.set_selected_option_text(*filling_content.select_text);
  }

  // Sometimes the field can be cleared by Autofill instead of being filled
  // (e.g. payments swapping) and in those cases
  // `is_autofilled_according_to_renderer` is set to false.
  //
  // Moreover, Glic-triggered filling operations must be done without setting
  // a blue background.
  bool should_mark_as_autofilled =
      !filling_content.value.empty() &&
      (trigger_source != AutofillTriggerSource::kGlic ||
       action_persistence == mojom::ActionPersistence::kPreview);

  // This is an abuse of naming. `is_autofilled_according_to_renderer` is being
  // set here so that the form is sent to the renderer and the renderer is able
  // to fill them and update the background accordingly.
  field_data.set_is_autofilled_according_to_renderer(should_mark_as_autofilled);
}

void FormFiller::UpdateCacheOnFill(
    FormStructure& form,
    base::span<const FormFieldData> browser_filled_fields,
    const base::flat_set<FieldGlobalId>& safe_filled_field_ids,
    const absl::flat_hash_map<FieldGlobalId, FieldType>& filled_field_types,
    const AugmentedFillingPayload& augmented_filling_payload) const {
  const auto is_newly_autofilled_field_map =
      base::MakeFlatMap<FieldGlobalId, bool>(
          browser_filled_fields, {}, [](const FormFieldData& field) {
            // FormFiller::FillField() does not always set
            // `field.is_autofilled_according_to_renderer()` to true, so we
            // inspect the value instead.
            return std::pair(field.global_id(), !field.value().empty());
          });
  for (const std::unique_ptr<AutofillField>& field : form) {
    if (!safe_filled_field_ids.contains(field->global_id())) {
      continue;
    }
    const FieldType& autofilled_type =
        CHECK_DEREF(base::FindOrNull(filled_field_types, field->global_id()));
    const bool is_newly_autofilled = CHECK_DEREF(
        base::FindOrNull(is_newly_autofilled_field_map, field->global_id()));
    const FillingProduct filling_product =
        augmented_filling_payload.filling_product();

    if (is_newly_autofilled) {
      field->AddFieldModifier(FieldModifier::kAutofill);
    } else {
      field->RemoveFieldModifier(FieldModifier::kAutofill, /*pass_key=*/{});
    }
    field->set_filling_product(filling_product);
    field->set_autofilled_type(autofilled_type);
    if (filling_product == FillingProduct::kAddress) {
      field->set_autofill_source_profile_guid(
          std::get<const AutofillProfile*>(augmented_filling_payload.variant)
              ->guid());
    }
  }
}

void FormFiller::AppendFillLogEvents(
    FormStructure& form,
    AutofillField& trigger_field,
    const base::flat_set<FieldGlobalId>& safe_field_ids,
    const base::flat_map<FieldGlobalId, DenseSet<FieldFillingSkipReason>>&
        skip_reasons,
    const FillingPayload& filling_payload,
    bool is_refill) {
  std::string country_code;
  if (const AutofillProfile* const* address =
          std::get_if<const AutofillProfile*>(&filling_payload)) {
    country_code =
        base::UTF16ToUTF8((*address)->GetRawInfo(ADDRESS_HOME_COUNTRY));
  }
  TriggerFillFieldLogEvent trigger_fill_field_log_event =
      TriggerFillFieldLogEvent{
          .data_type = GetFillDataTypeFromFillingPayload(filling_payload),
          .associated_country_code = country_code,
          .timestamp = base::Time::Now()};
  trigger_field.AppendLogEventIfNotRepeated(trigger_fill_field_log_event);
  FillEventId fill_event_id = trigger_fill_field_log_event.fill_event_id;

  for (const std::unique_ptr<AutofillField>& field : form.fields()) {
    const FieldGlobalId field_id = field->global_id();
    const bool has_value_before = !field->value().empty();
    const FieldFillingSkipReason skip_reason =
        skip_reasons.at(field_id).empty() ? FieldFillingSkipReason::kNotSkipped
                                          : *skip_reasons.at(field_id).begin();
    if (skip_reason == FieldFillingSkipReason::kNotSkipped) {
      field->AppendLogEventIfNotRepeated(FillFieldLogEvent{
          .fill_event_id = fill_event_id,
          .had_value_before_filling = ToOptionalBoolean(has_value_before),
          .autofill_skipped_status = skip_reason,
          .was_autofilled_before_security_policy = OptionalBoolean::kTrue,
          .had_value_after_filling =
              ToOptionalBoolean(safe_field_ids.contains(field_id)),
          .filling_prevented_by_iframe_security_policy =
              OptionalBoolean::kFalse,
          .was_refill = ToOptionalBoolean(is_refill),
      });
    } else {
      const bool skipped_because_of_security_policy =
          skip_reasons.at(field_id).size() == 1 &&
          skip_reason == FieldFillingSkipReason::kIframeSecurityPolicy;
      field->AppendLogEventIfNotRepeated(FillFieldLogEvent{
          .fill_event_id = fill_event_id,
          .had_value_before_filling = ToOptionalBoolean(has_value_before),
          .autofill_skipped_status = skip_reason,
          .was_autofilled_before_security_policy =
              skipped_because_of_security_policy ? OptionalBoolean::kTrue
                                                 : OptionalBoolean::kFalse,
          .had_value_after_filling = ToOptionalBoolean(has_value_before),
          .filling_prevented_by_iframe_security_policy =
              skipped_because_of_security_policy ? OptionalBoolean::kTrue
                                                 : OptionalBoolean::kUndefined,
          .was_refill = ToOptionalBoolean(is_refill),
      });
    }
  }
}

void FormFiller::LogFillingInternal(
    mojom::ActionPersistence action_persistence,
    const FormStructure& form,
    RefillOptions refill_options,
    FillingProduct filling_product,
    const base::flat_map<FieldGlobalId,
                         base::expected<FormFiller::ValueAndTypeAndOverride,
                                        std::string>>& filling_content,
    const base::flat_map<FieldGlobalId, DenseSet<FieldFillingSkipReason>>&
        skip_reasons) {
  LogBuffer buffer(IsLoggingActive(log_manager()));
  LOG_AF(buffer) << "action_persistence: "
                 << ActionPersistenceToString(action_persistence) << Br{};
  LOG_AF(buffer) << "filling product: "
                 << FillingProductToString(filling_product) << Br{};
  LOG_AF(buffer) << "is refill: " << refill_options.is_refill() << Br{};
  LOG_AF(buffer) << form << Br{};
  LOG_AF(buffer) << Tag{"table"};

  for (size_t i = 0; i < form.fields().size(); ++i) {
    const AutofillField& field = CHECK_DEREF(form.field(i));
    const base::expected<ValueAndTypeAndOverride, std::string>&
        expected_content = filling_content.at(field.global_id());
    if (!skip_reasons.at(field.global_id()).empty()) {
      const FieldFillingSkipReason skip_reason =
          *skip_reasons.at(field.global_id()).begin();
      LOG_AF(buffer) << Tr{} << base::StringPrintf("Field %zu", i)
                     << GetSkipFieldFillLogMessage(skip_reason) << " "
                     << expected_content.error_or("");
      continue;
    }
    CHECK(expected_content.has_value());

    const bool has_value_before = !field.value().empty();
    const bool has_value_after = !expected_content->value.empty();
    const bool is_autofilled_before =
        field.last_modifier() == FieldModifier::kAutofill;
    const bool is_autofilled_after = has_value_after;
    LOG_AF(buffer)
        << Tr{}
        << base::StringPrintf(
               "Field %zu Fillable - has value: %d->%d; autofilled: %d->%d.", i,
               has_value_before, has_value_after, is_autofilled_before,
               is_autofilled_after);
  }

  LOG_AF(buffer) << CTag{"table"};
  LOG_AF(log_manager()) << LoggingScope::kFilling
                        << LogMessage::kSendFillingData << Br{}
                        << std::move(buffer);
}

}  // namespace autofill
