chromium/ios/chrome/browser/autofill/ui_bundled/authentication/card_unmask_authentication_selection_mediator.mm

// 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.

#import "ios/chrome/browser/autofill/ui_bundled/authentication/card_unmask_authentication_selection_mediator.h"

#import "base/memory/weak_ptr.h"
#import "base/strings/sys_string_conversions.h"
#import "components/autofill/core/browser/ui/payments/card_unmask_authentication_selection_dialog_controller_impl.h"
#import "ios/chrome/browser/autofill/ui_bundled/authentication/card_unmask_authentication_selection_mediator_delegate.h"
#import "ios/chrome/browser/autofill/ui_bundled/authentication/card_unmask_authentication_selection_mutator_bridge.h"

namespace {
autofill::CardUnmaskAuthenticationSelectionDialog*
ReturnMediatorIgnoreControllerArg(
    CardUnmaskAuthenticationSelectionMediator* mediator,
    autofill::CardUnmaskAuthenticationSelectionDialogController*
        _unused_controller) {
  return mediator;
}
}  // namespace

CardUnmaskAuthenticationSelectionMediator::
    CardUnmaskAuthenticationSelectionMediator(
        base::WeakPtr<
            autofill::CardUnmaskAuthenticationSelectionDialogControllerImpl>
            model_controller,
        id<CardUnmaskAuthenticationSelectionConsumer> consumer)
    : model_controller_(model_controller), consumer_(consumer) {
  mutator_bridge_ = [[CardUnmaskAuthenticationSelectionMutatorBridge alloc]
      initWithTarget:weak_ptr_factory_.GetWeakPtr()];
  model_controller_->ShowDialog(
      base::BindOnce(&ReturnMediatorIgnoreControllerArg, this));
  [consumer_ setHeaderTitle:base::SysUTF16ToNSString(
                                model_controller_->GetWindowTitle())];
  [consumer_ setHeaderText:base::SysUTF16ToNSString(
                               model_controller_->GetContentHeaderText())];
  [consumer_ setCardUnmaskOptions:ConvertChallengeOptions()];
  [consumer_ setFooterText:base::SysUTF16ToNSString(
                               model_controller_->GetContentFooterText())];
  [consumer_
      setChallengeAcceptanceLabel:base::SysUTF16ToNSString(
                                      model_controller_->GetOkButtonLabel())];
}

CardUnmaskAuthenticationSelectionMediator::
    ~CardUnmaskAuthenticationSelectionMediator() {
  if (!was_dismissed_ && model_controller_) {
    // Our coordinator is stopping (e.g. closing Chromium, or view has been
    // swiped away). We must call OnDialogClosed on the model_controller_ before
    // this mediator is destroyed.
    model_controller_->OnDialogClosed(
        /*user_closed_dialog=*/true, /*server_success=*/false);
  }
}

// Implementation of CardUnmaskAuthenticationSelectionMutatorBridgeTarget
// follows:

void CardUnmaskAuthenticationSelectionMediator::DidSelectChallengeOption(
    CardUnmaskChallengeOptionIOS* option) {
  model_controller_->SetSelectedChallengeOptionId(option.id);
  // The done button label changes in response.
  [consumer_
      setChallengeAcceptanceLabel:base::SysUTF16ToNSString(
                                      model_controller_->GetOkButtonLabel())];
}

void CardUnmaskAuthenticationSelectionMediator::DidAcceptSelection() {
  model_controller_->OnOkButtonClicked();
}

void CardUnmaskAuthenticationSelectionMediator::DidCancelSelection() {
  Dismiss(/*user_closed_dialog=*/true, /*server_success=*/false);
}

// Implemention of autofill::CardUnmaskAuthenticationSelectionDialog follows:

void CardUnmaskAuthenticationSelectionMediator::Dismiss(bool user_closed_dialog,
                                                        bool server_success) {
  DCHECK(!was_dismissed_);
  was_dismissed_ = true;
  model_controller_->OnDialogClosed(user_closed_dialog, server_success);
  // If the user dismissed the authentication selection, then the dismissal
  // needs to be delegated up through our delegate (a coordinator).
  // If Dismiss() was called after a response from the server, then we expect
  // another prompt to be initiated without dismissal of the overall flow.
  if (user_closed_dialog) {
    [delegate_ dismissAuthenticationSelection];
  }
}

void CardUnmaskAuthenticationSelectionMediator::UpdateContent() {
  [consumer_ enterPendingState];
}

id<CardUnmaskAuthenticationSelectionMutator>
CardUnmaskAuthenticationSelectionMediator::AsMutator() {
  return mutator_bridge_;
}

// TODO(crbug.com/40282545): Once the ViewController is implemented, handle
// cancelling and pushing ok by implementing the view controller's mutator.

NSArray<CardUnmaskChallengeOptionIOS*>*
CardUnmaskAuthenticationSelectionMediator::ConvertChallengeOptions() {
  const std::vector<autofill::CardUnmaskChallengeOption>& autofill_options =
      model_controller_->GetChallengeOptions();
  NSMutableArray* ios_options =
      [NSMutableArray arrayWithCapacity:autofill_options.size()];
  for (auto option : autofill_options) {
    [ios_options
        addObject:[CardUnmaskChallengeOptionIOS
                      convertFrom:option
                        modeLabel:model_controller_->GetAuthenticationModeLabel(
                                      option)]];
  }
  return ios_options;
}