// Copyright 2013 The Chromium Authors. All rights reserved.
// 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/autofill_test_utils.h"

#include <string>

#include "base/guid.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/testing_pref_store.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"

using base::ASCIIToUTF16;

namespace autofill {
namespace test {

namespace {

std::string GetRandomCardNumber() {
  const size_t length = 16;
  std::string value;
  value.reserve(length);
  for (size_t i = 0; i < length; ++i)
    value.push_back(static_cast<char>(base::RandInt('0', '9')));
  return value;
}

}  // namespace

std::unique_ptr<PrefService> PrefServiceForTesting() {
  scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
      new user_prefs::PrefRegistrySyncable());
  return PrefServiceForTesting(registry.get());
}

std::unique_ptr<PrefService> PrefServiceForTesting(
    user_prefs::PrefRegistrySyncable* registry) {
  AutofillManager::RegisterProfilePrefs(registry);

  PrefServiceFactory factory;
  factory.set_user_prefs(base::MakeRefCounted<TestingPrefStore>());
  return factory.Create(registry);
}

void CreateTestFormField(const char* label,
                         const char* name,
                         const char* value,
                         const char* type,
                         FormFieldData* field) {
  field->label = ASCIIToUTF16(label);
  field->name = ASCIIToUTF16(name);
  field->value = ASCIIToUTF16(value);
  field->form_control_type = type;
  field->is_focusable = true;
}

void CreateTestSelectField(const char* label,
                           const char* name,
                           const char* value,
                           const std::vector<const char*>& values,
                           const std::vector<const char*>& contents,
                           size_t select_size,
                           FormFieldData* field) {
  // Fill the base attributes.
  CreateTestFormField(label, name, value, "select-one", field);

  std::vector<base::string16> values16(select_size);
  for (size_t i = 0; i < select_size; ++i)
    values16[i] = base::UTF8ToUTF16(values[i]);

  std::vector<base::string16> contents16(select_size);
  for (size_t i = 0; i < select_size; ++i)
    contents16[i] = base::UTF8ToUTF16(contents[i]);

  field->option_values = values16;
  field->option_contents = contents16;
}

void CreateTestSelectField(const std::vector<const char*>& values,
                           FormFieldData* field) {
  CreateTestSelectField("", "", "", values, values, values.size(), field);
}

void CreateTestAddressFormData(FormData* form) {
  std::vector<ServerFieldTypeSet> types;
  CreateTestAddressFormData(form, &types);
}

void CreateTestAddressFormData(FormData* form,
                               std::vector<ServerFieldTypeSet>* types) {
  form->name = ASCIIToUTF16("MyForm");
  form->origin = GURL("http://myform.com/form.html");
  form->action = GURL("http://myform.com/submit.html");
  form->main_frame_origin =
      url::Origin::Create(GURL("https://myform_root.com/form.html"));
  types->clear();

  FormFieldData field;
  ServerFieldTypeSet type_set;
  test::CreateTestFormField("First Name", "firstname", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(NAME_FIRST);
  types->push_back(type_set);
  test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(NAME_MIDDLE);
  types->push_back(type_set);
  test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(NAME_LAST);
  types->push_back(type_set);
  test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(ADDRESS_HOME_LINE1);
  types->push_back(type_set);
  test::CreateTestFormField("Address Line 2", "addr2", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(ADDRESS_HOME_LINE2);
  types->push_back(type_set);
  test::CreateTestFormField("City", "city", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(ADDRESS_HOME_CITY);
  types->push_back(type_set);
  test::CreateTestFormField("State", "state", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(ADDRESS_HOME_STATE);
  types->push_back(type_set);
  test::CreateTestFormField("Postal Code", "zipcode", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(ADDRESS_HOME_ZIP);
  types->push_back(type_set);
  test::CreateTestFormField("Country", "country", "", "text", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(ADDRESS_HOME_COUNTRY);
  types->push_back(type_set);
  test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(PHONE_HOME_WHOLE_NUMBER);
  types->push_back(type_set);
  test::CreateTestFormField("Email", "email", "", "email", &field);
  form->fields.push_back(field);
  type_set.clear();
  type_set.insert(EMAIL_ADDRESS);
  types->push_back(type_set);
}

void CreateTestPersonalInformationFormData(FormData* form) {
  form->name = ASCIIToUTF16("MyForm");
  form->origin = GURL("http://myform.com/form.html");
  form->action = GURL("http://myform.com/submit.html");
  form->main_frame_origin =
      url::Origin::Create(GURL("https://myform_root.com/form.html"));

  FormFieldData field;
  ServerFieldTypeSet type_set;
  test::CreateTestFormField("First Name", "firstname", "", "text", &field);
  form->fields.push_back(field);
  test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
  form->fields.push_back(field);
  test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
  form->fields.push_back(field);
  test::CreateTestFormField("Email", "email", "", "email", &field);
  form->fields.push_back(field);
}

void CreateTestCreditCardFormData(FormData* form,
                                  bool is_https,
                                  bool use_month_type,
                                  bool split_names) {
  form->name = ASCIIToUTF16("MyForm");
  if (is_https) {
    form->origin = GURL("https://myform.com/form.html");
    form->action = GURL("https://myform.com/submit.html");
    form->main_frame_origin =
        url::Origin::Create(GURL("https://myform_root.com/form.html"));
  } else {
    form->origin = GURL("http://myform.com/form.html");
    form->action = GURL("http://myform.com/submit.html");
    form->main_frame_origin =
        url::Origin::Create(GURL("http://myform_root.com/form.html"));
  }

  FormFieldData field;
  if (split_names) {
    test::CreateTestFormField("First Name on Card", "firstnameoncard", "",
                              "text", &field);
    field.autocomplete_attribute = "cc-given-name";
    form->fields.push_back(field);
    test::CreateTestFormField("Last Name on Card", "lastnameoncard", "", "text",
                              &field);
    field.autocomplete_attribute = "cc-family-name";
    form->fields.push_back(field);
    field.autocomplete_attribute = "";
  } else {
    test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
    form->fields.push_back(field);
  }
  test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
  form->fields.push_back(field);
  if (use_month_type) {
    test::CreateTestFormField("Expiration Date", "ccmonth", "", "month",
                              &field);
    form->fields.push_back(field);
  } else {
    test::CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
    form->fields.push_back(field);
    test::CreateTestFormField("", "ccyear", "", "text", &field);
    form->fields.push_back(field);
  }
  test::CreateTestFormField("CVC", "cvc", "", "text", &field);
  form->fields.push_back(field);
}

inline void check_and_set(
    FormGroup* profile, ServerFieldType type, const char* value) {
  if (value)
    profile->SetRawInfo(type, base::UTF8ToUTF16(value));
}

AutofillProfile GetFullValidProfileForCanada() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile, "Alice", "", "Wonderland", "alice@wonderland.ca",
                 "Fiction", "666 Notre-Dame Ouest", "Apt 8", "Montreal", "QC",
                 "H3B 2T9", "CA", "15141112233");
  return profile;
}

AutofillProfile GetFullValidProfileForChina() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile, "John", "H.", "Doe", "johndoe@google.cn", "Google",
                 "100 Century Avenue", "", "赫章县", "毕节地区", "贵州省",
                 "200120", "CN", "+86-21-6133-7666");
  return profile;
}

AutofillProfile GetFullProfile() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile,
                 "John",
                 "H.",
                 "Doe",
                 "johndoe@hades.com",
                 "Underworld",
                 "666 Erebus St.",
                 "Apt 8",
                 "Elysium", "CA",
                 "91111",
                 "US",
                 "16502111111");
  return profile;
}

AutofillProfile GetFullProfile2() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile,
                 "Jane",
                 "A.",
                 "Smith",
                 "jsmith@example.com",
                 "ACME",
                 "123 Main Street",
                 "Unit 1",
                 "Greensdale", "MI",
                 "48838",
                 "US",
                 "13105557889");
  return profile;
}

AutofillProfile GetFullCanadianProfile() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile, "Wayne", "", "Gretzky", "wayne@hockey.com", "NHL",
                 "123 Hockey rd.", "Apt 8", "Moncton", "New Brunswick",
                 "E1A 0A6", "CA", "15068531212");
  return profile;
}

AutofillProfile GetIncompleteProfile1() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile, "John", "H.", "Doe", "jsmith@example.com", "ACME",
                 "123 Main Street", "Unit 1", "Greensdale", "MI", "48838", "US",
                 "");
  return profile;
}

AutofillProfile GetIncompleteProfile2() {
  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
  SetProfileInfo(&profile, "", "", "", "jsmith@example.com", "", "", "", "", "",
                 "", "", "");
  return profile;
}

AutofillProfile GetVerifiedProfile() {
  AutofillProfile profile(GetFullProfile());
  profile.set_origin(kSettingsOrigin);
  return profile;
}

AutofillProfile GetVerifiedProfile2() {
  AutofillProfile profile(GetFullProfile2());
  profile.set_origin(kSettingsOrigin);
  return profile;
}

CreditCard GetCreditCard() {
  CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
  SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
                    "11", "2022", "1");
  return credit_card;
}

CreditCard GetCreditCard2() {
  CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
  SetCreditCardInfo(&credit_card, "Someone Else", "378282246310005" /* AmEx */,
                    "07", "2022", "1");
  return credit_card;
}

CreditCard GetVerifiedCreditCard() {
  CreditCard credit_card(GetCreditCard());
  credit_card.set_origin(kSettingsOrigin);
  return credit_card;
}

CreditCard GetVerifiedCreditCard2() {
  CreditCard credit_card(GetCreditCard2());
  credit_card.set_origin(kSettingsOrigin);
  return credit_card;
}

CreditCard GetMaskedServerCard() {
  CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
  test::SetCreditCardInfo(&credit_card, "Bonnie Parker",
                          "2109" /* Mastercard */, "12", "2020", "1");
  credit_card.SetNetworkForMaskedCard(kMasterCard);
  return credit_card;
}

CreditCard GetMaskedServerCardAmex() {
  CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "b456");
  test::SetCreditCardInfo(&credit_card, "Justin Thyme", "8431" /* Amex */, "9",
                          "2020", "1");
  credit_card.SetNetworkForMaskedCard(kAmericanExpressCard);
  return credit_card;
}

CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) {
  static const char* const kNetworks[] = {
      kAmericanExpressCard,
      kDinersCard,
      kDiscoverCard,
      kEloCard,
      kGenericCard,
      kJCBCard,
      kMasterCard,
      kMirCard,
      kUnionPay,
      kVisaCard,
  };
  constexpr size_t kNumNetworks = sizeof(kNetworks) / sizeof(kNetworks[0]);
  base::Time::Exploded now;
  base::Time::Now().LocalExplode(&now);

  CreditCard credit_card =
      (record_type == CreditCard::LOCAL_CARD)
          ? CreditCard(base::GenerateGUID(), kEmptyOrigin)
          : CreditCard(record_type, base::GenerateGUID().substr(24));
  test::SetCreditCardInfo(
      &credit_card, "Justin Thyme", GetRandomCardNumber().c_str(),
      base::StringPrintf("%d", base::RandInt(1, 12)).c_str(),
      base::StringPrintf("%d", now.year + base::RandInt(1, 4)).c_str(), "1");
  if (record_type == CreditCard::MASKED_SERVER_CARD) {
    credit_card.SetNetworkForMaskedCard(
        kNetworks[base::RandInt(0, kNumNetworks - 1)]);
  }

  return credit_card;
}

void SetProfileInfo(AutofillProfile* profile,
                    const char* first_name,
                    const char* middle_name,
                    const char* last_name,
                    const char* email,
                    const char* company,
                    const char* address1,
                    const char* address2,
                    const char* dependent_locality,
                    const char* city,
                    const char* state,
                    const char* zipcode,
                    const char* country,
                    const char* phone) {
  check_and_set(profile, NAME_FIRST, first_name);
  check_and_set(profile, NAME_MIDDLE, middle_name);
  check_and_set(profile, NAME_LAST, last_name);
  check_and_set(profile, EMAIL_ADDRESS, email);
  check_and_set(profile, COMPANY_NAME, company);
  check_and_set(profile, ADDRESS_HOME_LINE1, address1);
  check_and_set(profile, ADDRESS_HOME_LINE2, address2);
  check_and_set(profile, ADDRESS_HOME_DEPENDENT_LOCALITY, dependent_locality);
  check_and_set(profile, ADDRESS_HOME_CITY, city);
  check_and_set(profile, ADDRESS_HOME_STATE, state);
  check_and_set(profile, ADDRESS_HOME_ZIP, zipcode);
  check_and_set(profile, ADDRESS_HOME_COUNTRY, country);
  check_and_set(profile, PHONE_HOME_WHOLE_NUMBER, phone);
}

void SetProfileInfo(AutofillProfile* profile,
                    const char* first_name,
                    const char* middle_name,
                    const char* last_name,
                    const char* email,
                    const char* company,
                    const char* address1,
                    const char* address2,
                    const char* city,
                    const char* state,
                    const char* zipcode,
                    const char* country,
                    const char* phone) {
  check_and_set(profile, NAME_FIRST, first_name);
  check_and_set(profile, NAME_MIDDLE, middle_name);
  check_and_set(profile, NAME_LAST, last_name);
  check_and_set(profile, EMAIL_ADDRESS, email);
  check_and_set(profile, COMPANY_NAME, company);
  check_and_set(profile, ADDRESS_HOME_LINE1, address1);
  check_and_set(profile, ADDRESS_HOME_LINE2, address2);
  check_and_set(profile, ADDRESS_HOME_CITY, city);
  check_and_set(profile, ADDRESS_HOME_STATE, state);
  check_and_set(profile, ADDRESS_HOME_ZIP, zipcode);
  check_and_set(profile, ADDRESS_HOME_COUNTRY, country);
  check_and_set(profile, PHONE_HOME_WHOLE_NUMBER, phone);
}

void SetProfileInfoWithGuid(AutofillProfile* profile,
    const char* guid, const char* first_name, const char* middle_name,
    const char* last_name, const char* email, const char* company,
    const char* address1, const char* address2, const char* city,
    const char* state, const char* zipcode, const char* country,
    const char* phone) {
  if (guid)
    profile->set_guid(guid);
  SetProfileInfo(profile, first_name, middle_name, last_name, email,
                 company, address1, address2, city, state, zipcode, country,
                 phone);
}

void SetCreditCardInfo(CreditCard* credit_card,
                       const char* name_on_card,
                       const char* card_number,
                       const char* expiration_month,
                       const char* expiration_year,
                       const std::string& billing_address_id) {
  check_and_set(credit_card, CREDIT_CARD_NAME_FULL, name_on_card);
  check_and_set(credit_card, CREDIT_CARD_NUMBER, card_number);
  check_and_set(credit_card, CREDIT_CARD_EXP_MONTH, expiration_month);
  check_and_set(credit_card, CREDIT_CARD_EXP_4_DIGIT_YEAR, expiration_year);
  credit_card->set_billing_address_id(billing_address_id);
}

void DisableSystemServices(PrefService* prefs) {
  // Use a mock Keychain rather than the OS one to store credit card data.
  OSCryptMocker::SetUp();
}

void ReenableSystemServices() {
  OSCryptMocker::TearDown();
}

void SetServerCreditCards(AutofillTable* table,
                          const std::vector<CreditCard>& cards) {
  std::vector<CreditCard> as_masked_cards = cards;
  for (CreditCard& card : as_masked_cards) {
    card.set_record_type(CreditCard::MASKED_SERVER_CARD);
    card.SetNumber(card.LastFourDigits());
    card.SetNetworkForMaskedCard(card.network());
  }
  table->SetServerCreditCards(as_masked_cards);

  for (const CreditCard& card : cards) {
    if (card.record_type() != CreditCard::FULL_SERVER_CARD)
      continue;
    ASSERT_TRUE(table->UnmaskServerCreditCard(card, card.number()));
  }
}

void FillUploadField(AutofillUploadContents::Field* field,
                     unsigned signature,
                     const char* name,
                     const char* control_type,
                     const char* autocomplete,
                     unsigned autofill_type) {
  field->set_signature(signature);
  if (name)
    field->set_name(name);
  if (control_type)
    field->set_type(control_type);
  if (autocomplete)
    field->set_autocomplete(autocomplete);
  field->set_autofill_type(autofill_type);
}

void FillQueryField(AutofillQueryContents::Form::Field* field,
                    unsigned signature,
                    const char* name,
                    const char* control_type) {
  field->set_signature(signature);
  if (name)
    field->set_name(name);
  if (control_type)
    field->set_type(control_type);
}

void GenerateTestAutofillPopup(
    AutofillExternalDelegate* autofill_external_delegate) {
  int query_id = 1;
  FormData form;
  FormFieldData field;
  field.is_focusable = true;
  field.should_autocomplete = true;
  gfx::RectF bounds(100.f, 100.f);
  autofill_external_delegate->OnQuery(query_id, form, field, bounds);

  std::vector<Suggestion> suggestions;
  suggestions.push_back(Suggestion(base::ASCIIToUTF16("Test suggestion")));
  autofill_external_delegate->OnSuggestionsReturned(
      query_id, suggestions, /*autoselect_first_suggestion=*/false);
}

std::string ObfuscatedCardDigitsAsUTF8(const std::string& str) {
  return base::UTF16ToUTF8(
      internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16(str)));
}

std::string NextYear() {
  base::Time::Exploded now;
  base::Time::Now().LocalExplode(&now);
  return std::to_string(now.year + 1);
}
std::string LastYear() {
  base::Time::Exploded now;
  base::Time::Now().LocalExplode(&now);
  return std::to_string(now.year - 1);
}

}  // namespace test
}  // namespace autofill
