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

#include "chrome/browser/ui/autofill/address_editor_controller.h"

#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/callback_list.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/global_features.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/grit/generated_resources.h"
#include "components/application_locale_storage/application_locale_storage.h"
#include "components/autofill/core/browser/country_type.h"
#include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/ui/addresses/autofill_address_util.h"
#include "components/variations/service/variations_service.h"
#include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
#include "third_party/libaddressinput/messages.h"
#include "ui/base/l10n/l10n_util.h"

namespace autofill {

AddressEditorController::AddressEditorController(
    const AutofillProfile& profile_to_edit,
    PersonalDataManager* pdm,
    bool is_validatable)
    : profile_to_edit_(profile_to_edit),
      pdm_(*pdm),
      locale_(g_browser_process->GetFeatures()
                  ->application_locale_storage()
                  ->Get()),
      is_validatable_(is_validatable) {
  const variations::VariationsService* variations_service =
      g_browser_process->variations_service();
  countries_.SetCountries(
      GeoIpCountryCode(variations_service
                           ? variations_service->GetLatestCountry()
                           : std::string()),
      locale_);
  std::u16string profile_country_code =
      profile_to_edit_.GetRawInfo(ADDRESS_HOME_COUNTRY);
  UpdateEditorFields(base::UTF16ToASCII(profile_country_code));
}

AddressEditorController::~AddressEditorController() = default;

CountryComboboxModel& AddressEditorController::GetCountryComboboxModel() {
  return countries_;
}

void AddressEditorController::UpdateEditorFields(
    const std::string& country_code) {
  editor_fields_.clear();

  std::vector<std::vector<AutofillAddressUIComponent>> components;
  GetAddressComponents(country_code, locale_,
                       /*include_literals=*/false, &components,
                       &language_code_);
  profile_to_edit_.set_language_code(language_code_);

  // Insert the Country combobox at the top.
  editor_fields_.emplace_back(
      ADDRESS_HOME_COUNTRY,
      l10n_util::GetStringUTF16(IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL),
      EditorField::LengthHint::HINT_LONG, /*is_required=*/false,
      EditorField::ControlType::COMBOBOX);

  for (const std::vector<AutofillAddressUIComponent>& line : components) {
    for (const AutofillAddressUIComponent& component : line) {
      EditorField::LengthHint length_hint =
          component.length_hint == AutofillAddressUIComponent::HINT_LONG
              ? EditorField::LengthHint::HINT_LONG
              : EditorField::LengthHint::HINT_SHORT;
      EditorField::ControlType control_type =
          component.field == ADDRESS_HOME_COUNTRY
              ? EditorField::ControlType::COMBOBOX
              : EditorField::ControlType::TEXTFIELD;

      editor_fields_.emplace_back(
          component.field, base::UTF8ToUTF16(component.name), length_hint,
          component.is_required, control_type);
    }
  }
  // Always add phone number and email at the end.
  editor_fields_.emplace_back(
      PHONE_HOME_WHOLE_NUMBER,
      l10n_util::GetStringUTF16(IDS_SETTINGS_AUTOFILL_ADDRESSES_PHONE),
      EditorField::LengthHint::HINT_SHORT, /*is_required=*/false,
      EditorField::ControlType::TEXTFIELD_NUMBER);

  editor_fields_.emplace_back(
      EMAIL_ADDRESS,
      l10n_util::GetStringUTF16(IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL),
      EditorField::LengthHint::HINT_LONG, /*is_required=*/false,
      EditorField::ControlType::TEXTFIELD);
}

void AddressEditorController::SetProfileInfo(FieldType type,
                                             const std::u16string& value) {
  // Since the countries combobox contains the country names, not the country
  // codes, and hence we should use `SetInfo()` to make sure they get converted
  // to country codes. Also use `SetInfo()` for `NAME_FULL` so that its
  // dependent nodes (NAME_FIRST, NAME_LAST, etc) are also updated. This does
  // not need to be done for addresses because it is handled internally inside
  // `SetRawInfo()`.
  if (type == ADDRESS_HOME_COUNTRY || type == NAME_FULL) {
    profile_to_edit_.SetInfoWithVerificationStatus(
        type, value, locale_, VerificationStatus::kUserVerified);
    return;
  }

  profile_to_edit_.SetRawInfoWithVerificationStatus(
      type, value, VerificationStatus::kUserVerified);
}

std::u16string AddressEditorController::GetProfileInfo(FieldType type) {
  // TDOD(mamir): Update the implementation to format strings properly.
  return profile_to_edit_.GetInfo(type, locale_);
}

const AutofillProfile& AddressEditorController::GetAddressProfile() {
  return profile_to_edit_;
}

void AddressEditorController::SetIsValid(bool is_valid) {
  bool should_notify = is_valid_ != is_valid;
  is_valid_ = is_valid;
  if (should_notify) {
    on_is_valid_change_callbacks_.Notify(is_valid);
  }
}

base::CallbackListSubscription
AddressEditorController::AddIsValidChangedCallback(
    OnIsValidChangeCallbackList::CallbackType callback) {
  return on_is_valid_change_callbacks_.Add(std::move(callback));
}

bool AddressEditorController::IsValid(const EditorField& field,
                                      std::u16string_view value) {
  if (is_validatable_ && field.is_required &&
      base::CollapseWhitespace(value, true).empty()) {
    return false;
  }

  return true;
}

}  // namespace autofill
