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

#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "components/application_locale_storage/application_locale_storage.h"
#import "components/autofill/core/browser/data_model/payments/credit_card.h"
#import "components/autofill/core/browser/data_quality/autofill_data_util.h"
#import "components/autofill/core/browser/data_quality/validation.h"
#import "components/autofill/core/common/credit_card_number_validation.h"
#import "components/autofill/ios/browser/credit_card_util.h"
#import "ios/chrome/browser/autofill/manual_fill/model/manual_fill_credit_card+CreditCard.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "url/gurl.h"

@implementation ManualFillCreditCard (CreditCardForm)

- (instancetype)initWithCreditCard:(const autofill::CreditCard&)creditCard
                              icon:(UIImage*)icon {
  NSString* GUID =
      base::SysUTF16ToNSString(base::ASCIIToUTF16(creditCard.guid()));
  NSString* network = base::SysUTF16ToNSString(creditCard.NetworkForDisplay());
  NSString* bankName =
      base::SysUTF16ToNSString(base::ASCIIToUTF16(creditCard.bank_name()));
  NSString* cardHolder = autofill::GetCreditCardName(
      creditCard,
      GetApplicationContext()->GetApplicationLocaleStorage()->Get());
  NSString* number = nil;
  if (creditCard.record_type() !=
      autofill::CreditCard::RecordType::kMaskedServerCard) {
    number = base::SysUTF16ToNSString(autofill::StripCardNumberSeparators(
        creditCard.GetRawInfo(autofill::CREDIT_CARD_NUMBER)));
  }

  BOOL canFillDirectly =
      (creditCard.record_type() !=
       autofill::CreditCard::RecordType::kMaskedServerCard) &&
      (creditCard.record_type() !=
           autofill::CreditCard::RecordType::kVirtualCard ||
       !creditCard.cvc().empty());

  // Unicode characters used in card number:
  //  - 0x0020 - Space.
  //  - 0x2060 - WORD-JOINER (makes string undivisible).
  constexpr char16_t separator[] = {0x2060, 0x0020, 0};
  const std::u16string digits = creditCard.LastFourDigits();
  NSString* obfuscatedNumber =
      base::SysUTF16ToNSString(autofill::CreditCard::GetMidlineEllipsisDots(4) +
                               std::u16string(separator) +
                               autofill::CreditCard::GetMidlineEllipsisDots(4) +
                               std::u16string(separator) +
                               autofill::CreditCard::GetMidlineEllipsisDots(4) +
                               std::u16string(separator) + digits);

  NSString* networkAndLastFourDigits =
      base::SysUTF16ToNSString(creditCard.NetworkAndLastFourDigits());

  // Use 2 digits year.
  NSString* expirationYear =
      [NSString stringWithFormat:@"%02d", creditCard.expiration_year() % 100];
  NSString* expirationMonth =
      [NSString stringWithFormat:@"%02d", creditCard.expiration_month()];

  NSString* CVC = nil;
  if (creditCard.record_type() ==
          autofill::CreditCard::RecordType::kVirtualCard ||
      creditCard.card_info_retrieval_enrollment_state() ==
          autofill::CreditCard::CardInfoRetrievalEnrollmentState::
              kRetrievalEnrolled) {
    if (creditCard.cvc().empty()) {
      // For virtual cards, if the CVC() value is empty, it means no
      // verification has been done and the `creditCard` object contains only
      // the obfuscated card information.
      CVC =
          base::SysUTF16ToNSString(autofill::CreditCard::GetMidlineEllipsisDots(
              autofill::GetCvcLengthForCardNetwork(creditCard.network())));
    } else {
      // If the CVC() value is non-empty, it means the a verification step has
      // been done and the `creditCard` object contains the full card
      // information.
      CVC = base::SysUTF16ToNSString(creditCard.cvc());
    }
  } else if (creditCard.record_type() ==
             autofill::CreditCard::RecordType::kLocalCard) {
    // For local card, the CVC should be shown.
    if (!creditCard.cvc().empty()) {
      CVC = base::SysUTF16ToNSString(creditCard.cvc());
    }
  } else {
    // For server card, the CVC should be masked.
    if (!creditCard.cvc().empty()) {
      CVC =
          base::SysUTF16ToNSString(autofill::CreditCard::GetMidlineEllipsisDots(
              autofill::GetCvcLengthForCardNetwork(creditCard.network())));
    }
  }

  return [self initWithGUID:GUID
                               network:network
                                  icon:icon
                              bankName:bankName
                            cardHolder:cardHolder
                                number:number
                      obfuscatedNumber:obfuscatedNumber
              networkAndLastFourDigits:networkAndLastFourDigits
                        expirationYear:expirationYear
                       expirationMonth:expirationMonth
                                   CVC:CVC
                            recordType:creditCard.record_type()
      cardInfoRetrievalEnrollmentState:
          creditCard.card_info_retrieval_enrollment_state()
                       canFillDirectly:canFillDirectly];
}

@end
