// Copyright 2025 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/views/autofill/payments/bnpl_tos_dialog.h"

#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "components/autofill/core/browser/data_model/payments/bnpl_issuer.h"
#include "components/autofill/core/browser/metrics/payments/bnpl_metrics.h"
#include "components/autofill/core/browser/payments/bnpl_util.h"
#include "components/autofill/core/browser/payments/constants.h"
#include "components/autofill/core/browser/ui/payments/bnpl_tos_controller.h"
#include "components/strings/grit/components_strings.h"
#include "components/tabs/public/tab_interface.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/separator.h"
#include "ui/views/controls/throbber.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view_class_properties.h"

using views::BoxLayout;
using views::BoxLayoutView;

namespace autofill {

BEGIN_METADATA(BnplTosDialog)
END_METADATA

DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(BnplTosDialog, kThrobberId);

BnplTosDialog::BnplTosDialog(
    base::WeakPtr<BnplTosController> controller,
    base::RepeatingCallback<void(const GURL&)> link_opener)
    : controller_(controller), link_opener_(link_opener) {
  // Set the ownership of the delegate, not the View. The View is owned by the
  // Widget as a child view.
  // TODO(crbug.com/338254375): Remove the following line once this is the
  // default state for widgets.
  SetOwnershipOfNewWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
  SetAcceptCallbackWithClose(
      base::BindRepeating(&BnplTosDialog::OnAccepted, base::Unretained(this)));
  SetCancelCallbackWithClose(
      base::BindRepeating(&BnplTosDialog::OnCancelled, base::Unretained(this)));

  ChromeLayoutProvider* chrome_layout_provider = ChromeLayoutProvider::Get();

  SetModalType(ui::mojom::ModalType::kChild);
  set_fixed_width(chrome_layout_provider->GetDistanceMetric(
      views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH));
  set_margins(chrome_layout_provider->GetDialogInsetsForContentType(
      views::DialogContentType::kControl, views::DialogContentType::kControl));
  SetShowCloseButton(false);
  SetButtonStyle(ui::mojom::DialogButton::kCancel, ui::ButtonStyle::kDefault);
  SetButtonLabel(ui::mojom::DialogButton::kOk, controller_->GetOkButtonLabel());
  SetButtonLabel(ui::mojom::DialogButton::kCancel,
                 controller_->GetCancelButtonLabel());
  SetLayoutManager(std::make_unique<BoxLayout>());

  container_view_ = AddChildView(std::make_unique<views::View>());
  container_view_->SetUseDefaultFillLayout(true);

  content_view_ =
      container_view_->AddChildView(std::make_unique<BoxLayoutView>());
  content_view_->SetOrientation(BoxLayout::Orientation::kVertical);
  content_view_->SetBetweenChildSpacing(
      chrome_layout_provider->GetDistanceMetric(
          views::DISTANCE_UNRELATED_CONTROL_VERTICAL));

  content_view_->AddChildView(CreateTextWithIconView(
      controller_->GetReviewText(), /*text_link_info=*/std::nullopt,
      ::features::IsRoundedIconsEnabled() ? vector_icons::kChecklistIcon
                                          : vector_icons::kChecklistOldIcon));

  content_view_->AddChildView(CreateTextWithIconView(
      controller_->GetApproveText(), /*text_link_info=*/std::nullopt,
      ::features::IsRoundedIconsEnabled() ? vector_icons::kReceiptLongIcon
                                          : vector_icons::kReceiptLongOldIcon));

  payments::TextWithLink link_text = controller_->GetLinkText();
  TextLinkInfo link_info;
  link_info.offset = link_text.offset;
  link_info.callback = base::BindRepeating(link_opener_, link_text.url);
  content_view_->AddChildView(CreateTextWithIconView(
      link_text.text, std::move(link_info),
      ::features::IsRoundedIconsEnabled() ? vector_icons::kAddLinkIcon
                                          : vector_icons::kAddLinkOldIcon));

  content_view_->AddChildView(std::make_unique<views::Separator>())
      ->SetProperty(
          views::kMarginsKey,
          gfx::Insets().set_top(ChromeLayoutProvider::Get()->GetDistanceMetric(
              DISTANCE_CONTENT_LIST_VERTICAL_MULTI)));

  content_view_->AddChildView(CreateLegalMessageView(
      controller_->GetLegalMessageLines(),
      base::UTF8ToUTF16(controller_->GetAccountInfo().GetEmail()),
      GetProfileAvatar(controller_->GetAccountInfo()), link_opener_));

  throbber_view_ =
      container_view_->AddChildView(std::make_unique<BoxLayoutView>());
  throbber_view_->SetVisible(false);
  throbber_view_->SetMainAxisAlignment(
      views::BoxLayout::MainAxisAlignment::kCenter);
  throbber_view_->SetCrossAxisAlignment(BoxLayout::CrossAxisAlignment::kCenter);
  throbber_ = throbber_view_->AddChildView(
      std::make_unique<views::Throbber>(kDialogThrobberDiameter));
  throbber_->SetProperty(views::kElementIdentifierKey,
                         BnplTosDialog::kThrobberId);
  throbber_->GetViewAccessibility().AnnouncePolitely(l10n_util::GetStringUTF16(
      IDS_AUTOFILL_BNPL_PROGRESS_DIALOG_LOADING_MESSAGE));
}

BnplTosDialog::~BnplTosDialog() = default;

void BnplTosDialog::AddedToWidget() {
  std::u16string title = controller_->GetTitle();
  // The view needs to be added to the widget before we can get the bubble frame
  // view.
  GetBubbleFrameView()->SetTitleView(
      std::make_unique<TitleWithIconAfterLabelView>(title, GetTitleIcon()));
  SetAccessibleWindowRole(ax::mojom::Role::kDialog);
  SetAccessibleTitle(
      l10n_util::GetStringFUTF16(IDS_AUTOFILL_BNPL_TOS_TITLE_DESCRIPTION, title,
                                 GetTitleIconAccessibilityString()));
}

void BnplTosDialog::OnWidgetInitialized() {
  views::DialogDelegateView::OnWidgetInitialized();
  GetOkButton()->RequestFocus();
}

TitleWithIconAfterLabelView::Icon BnplTosDialog::GetTitleIcon() const {
  bool is_wallet_branding_enabled =
      base::FeatureList::IsEnabled(features::kAutofillEnableWalletBranding);
  switch (controller_->GetIssuerId()) {
    case BnplIssuer::IssuerId::kBnplAffirm:
      return is_wallet_branding_enabled
                 ? TitleWithIconAfterLabelView::Icon::AFFIRM
                 : TitleWithIconAfterLabelView::Icon::GOOGLE_PAY_AND_AFFIRM;
    case BnplIssuer::IssuerId::kBnplZip:
      return is_wallet_branding_enabled
                 ? TitleWithIconAfterLabelView::Icon::ZIP
                 : TitleWithIconAfterLabelView::Icon::GOOGLE_PAY_AND_ZIP;
    // TODO(crbug.com/408268581): Handle Afterpay issuer enum value when adding
    // Afterpay to the BNPL flow.
    case BnplIssuer::IssuerId::kBnplAfterpay:
      return is_wallet_branding_enabled
                 ? TitleWithIconAfterLabelView::Icon::AFTERPAY
                 : TitleWithIconAfterLabelView::Icon::GOOGLE_PAY;
    case BnplIssuer::IssuerId::kBnplKlarna:
      return is_wallet_branding_enabled
                 ? TitleWithIconAfterLabelView::Icon::KLARNA
                 : TitleWithIconAfterLabelView::Icon::GOOGLE_PAY_AND_KLARNA;
  }
  NOTREACHED();
}

std::u16string BnplTosDialog::GetTitleIconAccessibilityString() const {
  switch (controller_->GetIssuerId()) {
    case BnplIssuer::IssuerId::kBnplAffirm:
      return l10n_util::GetStringUTF16(
          IDS_AUTOFILL_GOOGLE_PAY_AND_AFFIRM_LOGO_ACCESSIBLE_NAME);
    case BnplIssuer::IssuerId::kBnplZip:
      return l10n_util::GetStringUTF16(
          IDS_AUTOFILL_GOOGLE_PAY_AND_ZIP_LOGO_ACCESSIBLE_NAME);
    case BnplIssuer::IssuerId::kBnplAfterpay:
      return l10n_util::GetStringUTF16(
          IDS_AUTOFILL_GOOGLE_PAY_AND_AFTERPAY_LOGO_ACCESSIBLE_NAME);
    case BnplIssuer::IssuerId::kBnplKlarna:
      return l10n_util::GetStringUTF16(
          IDS_AUTOFILL_GOOGLE_PAY_AND_KLARNA_LOGO_ACCESSIBLE_NAME);
  }
  NOTREACHED();
}

bool BnplTosDialog::OnAccepted() {
  SetButtonEnabled(ui::mojom::DialogButton::kOk, false);

  throbber_->SizeToPreferredSize();
  throbber_->Start();
  content_view_->SetVisible(false);
  throbber_view_->SetVisible(true);

  // This call will destroy `this` and no members should be referenced
  // afterwards.
  controller_->OnUserAccepted();

  return false;
}

bool BnplTosDialog::OnCancelled() {
  // This call will destroy `this` and no members should be referenced
  // afterwards.
  controller_->OnUserCancelled();

  return false;
}

void BnplTosDialog::OnTabDetached(tabs::TabInterface* tab,
                                  tabs::TabInterface::DetachReason reason) {
  if (controller_ && reason == tabs::TabInterface::DetachReason::kDelete) {
    autofill_metrics::LogBnplTosDialogResult(
        autofill_metrics::BnplTosDialogResult::kTabOrBrowserClosed,
        controller_->GetIssuerId());
  }
}

}  // namespace autofill
