chromium/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm

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

#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h"

#import "base/metrics/histogram_functions.h"
#import "base/metrics/user_metrics.h"
#import "base/strings/sys_string_conversions.h"
#import "components/autofill/core/browser/data_model/credit_card.h"
#import "components/autofill/core/browser/payments_data_manager.h"
#import "components/autofill/core/browser/personal_data_manager.h"
#import "components/autofill/core/common/autofill_payments_features.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_util.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"

@implementation AutofillAddCreditCardMediator {
  // This property is for an interface which sends a response about saving the
  // credit card either the credit card is valid or it is invalid.
  __weak id<AddCreditCardMediatorDelegate> _addCreditCardMediatorDelegate;

  // Used for adding new CreditCard object.
  raw_ptr<autofill::PersonalDataManager> _personalDataManager;
}

- (instancetype)initWithDelegate:(id<AddCreditCardMediatorDelegate>)
                                     addCreditCardMediatorDelegate
             personalDataManager:(autofill::PersonalDataManager*)dataManager {
  self = [super init];

  if (self) {
    DCHECK(dataManager);
    _personalDataManager = dataManager;
    _addCreditCardMediatorDelegate = addCreditCardMediatorDelegate;
  }

  return self;
}

#pragma mark - AddCreditCardViewControllerDelegate

- (void)addCreditCardViewController:
            (AutofillAddCreditCardViewController*)viewController
        addCreditCardWithHolderName:(NSString*)cardHolderName
                         cardNumber:(NSString*)cardNumber
                    expirationMonth:(NSString*)expirationMonth
                     expirationYear:(NSString*)expirationYear
                       cardNickname:(NSString*)cardNickname {
  const std::string& appLocal = GetApplicationContext()->GetApplicationLocale();
  autofill::CreditCard creditCard =
      [AutofillCreditCardUtil creditCardWithHolderName:cardHolderName
                                            cardNumber:cardNumber
                                       expirationMonth:expirationMonth
                                        expirationYear:expirationYear
                                          cardNickname:cardNickname
                                              appLocal:appLocal];

  // Validates the credit card number, expiration date, and nickname.
  if (!creditCard.HasValidCardNumber()) {
    [_addCreditCardMediatorDelegate
        creditCardMediatorHasInvalidCardNumber:self];
    return;
  }

  if (!creditCard.HasValidExpirationDate()) {
    [_addCreditCardMediatorDelegate
        creditCardMediatorHasInvalidExpirationDate:self];
    return;
  }

  if (!autofill::CreditCard::IsNicknameValid(
          base::SysNSStringToUTF16(cardNickname))) {
    [_addCreditCardMediatorDelegate creditCardMediatorHasInvalidNickname:self];
    return;
  }

  autofill::CreditCard* savedCreditCard =
      _personalDataManager->payments_data_manager().GetCreditCardByNumber(
          base::SysNSStringToUTF8(cardNumber));

  // If the credit card number already exist in saved credit card
  // `savedCreditCard` then update saved credit card `savedCreditCardCopy`
  // with the new data.
  // Server cards information is not completely stored in the browser. We
  // can't tell for sure if there's an existing card with the same number. Then
  // even if we find an existing server card with the same number we still
  // create a local card with the data entered by the user.
  if (savedCreditCard != nil &&
      savedCreditCard->record_type() ==
          autofill::CreditCard::RecordType::kLocalCard) {
    autofill::CreditCard savedCreditCardCopy(*savedCreditCard);

    [AutofillCreditCardUtil updateCreditCard:&savedCreditCardCopy
                              cardHolderName:cardHolderName
                                  cardNumber:cardNumber
                             expirationMonth:expirationMonth
                              expirationYear:expirationYear
                                cardNickname:cardNickname
                                    appLocal:appLocal];

    _personalDataManager->payments_data_manager().UpdateCreditCard(
        savedCreditCardCopy);
  } else {
    base::RecordAction(
        base::UserMetricsAction("MobileAddCreditCard.CreditCardAdded"));
    base::UmaHistogramCounts100(
        "Autofill.PaymentMethods.SettingsPage."
        "StoredCreditCardCountBeforeCardAdded",
        _personalDataManager->payments_data_manager().GetCreditCards().size());
    _personalDataManager->payments_data_manager().AddCreditCard(creditCard);
  }

  [_addCreditCardMediatorDelegate creditCardMediatorDidFinish:self];
}

- (void)addCreditCardViewControllerDidCancel:
    (AutofillAddCreditCardViewController*)viewController {
  [_addCreditCardMediatorDelegate creditCardMediatorDidFinish:self];
}

- (bool)addCreditCardViewController:
            (AutofillAddCreditCardViewController*)viewController
            isValidCreditCardNumber:(NSString*)cardNumber {
  return [AutofillCreditCardUtil
      isValidCreditCardNumber:cardNumber
                     appLocal:GetApplicationContext()->GetApplicationLocale()];
}

- (bool)addCreditCardViewController:
            (AutofillAddCreditCardViewController*)viewController
    isValidCreditCardExpirationMonth:(NSString*)expirationMonth {
  return
      [AutofillCreditCardUtil isValidCreditCardExpirationMonth:expirationMonth];
}

- (bool)addCreditCardViewController:
            (AutofillAddCreditCardViewController*)viewController
    isValidCreditCardExpirationYear:(NSString*)expirationYear {
  return [AutofillCreditCardUtil
      isValidCreditCardExpirationYear:expirationYear
                             appLocal:GetApplicationContext()
                                          ->GetApplicationLocale()];
}

- (bool)addCreditCardViewController:
            (AutofillAddCreditCardViewController*)viewController
                isValidCardNickname:(NSString*)cardNickname {
  return [AutofillCreditCardUtil isValidCardNickname:cardNickname];
}

- (bool)addCreditCardViewController:
            (AutofillAddCreditCardViewController*)viewController
            isValidCreditCardNumber:(NSString*)cardNumber
                    expirationMonth:(NSString*)expirationMonth
                     expirationYear:(NSString*)expirationYear
                       cardNickname:(NSString*)cardNickname {
  const std::string& appLocal = GetApplicationContext()->GetApplicationLocale();
  return ([AutofillCreditCardUtil isValidCreditCardNumber:cardNumber
                                                 appLocal:appLocal] &&
          [AutofillCreditCardUtil
              isValidCreditCardExpirationMonth:expirationMonth] &&
          [AutofillCreditCardUtil isValidCreditCardExpirationYear:expirationYear
                                                         appLocal:appLocal] &&
          [AutofillCreditCardUtil isValidCardNickname:cardNickname]);
}

@end