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

#include <memory>
#include <string>
#include <string_view>

#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "chrome/browser/ui/autofill/payments/desktop_payments_window_manager.h"
#include "chrome/browser/ui/autofill/payments/desktop_payments_window_manager_test_api.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
#include "chrome/browser/ui/browser_window/public/global_browser_collection.h"
#include "chrome/browser/ui/test/test_browser_ui.h"
#include "chrome/browser/ui/views/autofill/payments/payments_window_user_consent_dialog_view.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "components/autofill/content/browser/test_autofill_client_injector.h"
#include "components/autofill/content/browser/test_content_autofill_client.h"
#include "components/autofill/core/browser/metrics/payments/bnpl_metrics.h"
#include "components/autofill/core/browser/metrics/payments/payments_window_metrics.h"
#include "components/autofill/core/browser/payments/card_unmask_challenge_option.h"
#include "components/autofill/core/browser/payments/constants.h"
#include "components/autofill/core/browser/payments/payments_autofill_client.h"
#include "components/autofill/core/browser/payments/payments_window_manager.h"
#include "components/autofill/core/browser/payments/test_payments_autofill_client.h"
#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/window/dialog_client_view.h"

namespace autofill::payments {
namespace {

class TestContentAutofillClientForWindowManagerTest
    : public TestContentAutofillClient {
 public:
  explicit TestContentAutofillClientForWindowManagerTest(
      content::WebContents* web_contents)
      : TestContentAutofillClient(web_contents) {
    GetPaymentsAutofillClient()->set_payments_network_interface(
        std::make_unique<TestPaymentsNetworkInterface>(nullptr, nullptr,
                                                       nullptr));
    GetPaymentsAutofillClient()->set_payments_window_manager(
        std::make_unique<DesktopPaymentsWindowManager>(this));
  }

  ~TestContentAutofillClientForWindowManagerTest() override = default;
};

constexpr std::string_view kTestUrl = "https://site.example/";
constexpr std::string_view kBnplInitialUrl = "https://www.bnplinitialurl.com/";
constexpr std::string_view kBnplSuccessUrlPrefix =
    "https://www.bnplsuccess.com/";
constexpr std::string_view kBnplFailureUrlPrefix =
    "https://www.bnplfailure.com/";
constexpr std::string_view kTestContextToken = "Test context token";
constexpr std::string_view kVcn3dsFlowEventsHistogramName =
    "Autofill.Vcn3ds.FlowEvents";
constexpr std::string_view kVcn3dsFlowEventsConsentAlreadyGivenHistogramName =
    "Autofill.Vcn3ds.FlowEvents.ConsentAlreadyGiven";
constexpr std::string_view kVcn3dsFlowEventsConsentNotGivenYetHistogramName =
    "Autofill.Vcn3ds.FlowEvents.ConsentNotGivenYet";
constexpr std::string_view kVcn3dsSuccessLatencyHistogramName =
    "Autofill.Vcn3ds.Latency.Success";
constexpr std::string_view kVcn3dsFailureLatencyHistogramName =
    "Autofill.Vcn3ds.Latency.Failure";

class DesktopPaymentsWindowManagerInteractiveUiTest : public UiBrowserTest {
 public:
  DesktopPaymentsWindowManagerInteractiveUiTest() = default;

  void ShowUi(const std::string& name) override {
    ui_test_utils::BrowserCreatedObserver browser_created_observer;
    if (name.find("Vcn3ds") != std::string::npos) {
      client()->set_last_committed_primary_main_frame_url(GURL(kTestUrl));

      PaymentsWindowManager::Vcn3dsContext context;
      context.card = test::GetVirtualCard();
      context.context_token = kTestContextToken;
      Vcn3dsChallengeOptionMetadata metadata;
      metadata.url_to_open = GURL(kTestUrl);
      metadata.success_query_param_name = "token";
      metadata.failure_query_param_name = "failure";
      context.challenge_option.vcn_3ds_metadata = std::move(metadata);
      context.completion_callback = authentication_complete_callback_.Get();
      context.user_consent_already_given =
          name.find("ConsentAlreadyGiven") != std::string::npos;
      ON_CALL(authentication_complete_callback_, Run)
          .WillByDefault(
              [this](PaymentsWindowManager::Vcn3dsAuthenticationResponse
                         authentication_response) {
                set_authentication_response(std::move(authentication_response));
              });
      window_manager().InitVcn3dsAuthentication(std::move(context));
    } else if (name.find("Bnpl") != std::string::npos) {
      PaymentsWindowManager::BnplContext context;
      context.issuer_id = BnplIssuer::IssuerId::kBnplAffirm;
      context.success_url_prefix = GURL(kBnplSuccessUrlPrefix);
      context.failure_url_prefix = GURL(kBnplFailureUrlPrefix);
      context.initial_url = GURL(kBnplInitialUrl);
      context.completion_callback = bnpl_popup_closed_callback_.Get();
      window_manager().InitBnplFlow(std::move(context));
    } else {
      NOTREACHED();
    }
    popup_browser_ = browser_created_observer.Wait();
  }

  bool VerifyUi() override {
    // There should be two browsers present, the original browser and the
    // pop-up's browser.
    if (GlobalBrowserCollection::GetInstance()->GetSize() != 2U) {
      return false;
    }

    auto* source_web_contents = GetOriginalPageWebContents();
    auto* popup_web_contents = GetPopupWebContents();

    // This ensures that there is no scripting relationship between the pop-up
    // and the original tab.
    if (source_web_contents->GetSiteInstance()->IsRelatedSiteInstance(
            popup_web_contents->GetSiteInstance())) {
      return false;
    }

    std::string test_name =
        testing::UnitTest::GetInstance()->current_test_info()->name();
    if (test_name.find("Vcn3ds") != std::string::npos) {
      if (popup_web_contents->GetVisibleURL() != GURL(kTestUrl)) {
        return false;
      }
    } else if (test_name.find("Bnpl") != std::string::npos) {
      if (popup_web_contents->GetVisibleURL() != GURL(kBnplInitialUrl)) {
        return false;
      }
    } else {
      NOTREACHED();
    }

    return true;
  }

  void WaitForUserDismissal() override {}

 protected:
  content::WebContents* GetOriginalPageWebContents() {
    // The original page is always created first.
    return browser()->GetTabStripModel()->GetActiveWebContents();
  }

  content::WebContents* GetPopupWebContents() {
    return popup_browser_->GetTabStripModel()->GetActiveWebContents();
  }

  BrowserWindowInterface* popup_browser() { return popup_browser_; }

  void ClosePopupAndWait() {
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, base::BindOnce(&content::WebContents::Close,
                                  GetPopupWebContents()->GetWeakPtr()));
    WaitForPopupClose();
  }

  void WaitForPopupClose() {
    base::RunLoop run_loop;
    base::RepeatingClosure popup_closed_closure = run_loop.QuitClosure();
    test_api(window_manager()).SetPopupClosedClosure(popup_closed_closure);
    run_loop.Run();
  }

  TestContentAutofillClientForWindowManagerTest* client() {
    return test_autofill_client_injector_[GetOriginalPageWebContents()];
  }

  DesktopPaymentsWindowManager& window_manager() {
    return *static_cast<DesktopPaymentsWindowManager*>(
        client()->GetPaymentsAutofillClient()->GetPaymentsWindowManager());
  }

  void set_authentication_response(
      PaymentsWindowManager::Vcn3dsAuthenticationResponse
          authentication_response) {
    authentication_response_ = std::move(authentication_response);
  }
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse>
  authentication_response() {
    return authentication_response_;
  }

  base::HistogramTester histogram_tester_;
  base::MockCallback<
      PaymentsWindowManager::OnVcn3dsAuthenticationCompleteCallback>
      authentication_complete_callback_;
  base::MockCallback<PaymentsWindowManager::OnBnplPopupClosedCallback>
      bnpl_popup_closed_callback_;

 private:
  TestAutofillClientInjector<TestContentAutofillClientForWindowManagerTest>
      test_autofill_client_injector_;

  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse>
      authentication_response_;

  raw_ptr<BrowserWindowInterface> popup_browser_;
};

// Tests that an error dialog is shown if there is no metadata returned from the
// server.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_EmptyMetadata_ErrorDialogShown) {
  PaymentsWindowManager::Vcn3dsContext context;
  context.card = test::GetVirtualCard();
  context.context_token = kTestContextToken;
  context.completion_callback = authentication_complete_callback_.Get();
  context.user_consent_already_given = true;
  window_manager().InitVcn3dsAuthentication(std::move(context));
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Tests that an error dialog is shown if there is no URL to open returned from
// the server.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_EmptyUrlToOpen_ErrorDialogShown) {
  PaymentsWindowManager::Vcn3dsContext context;
  context.card = test::GetVirtualCard();
  context.context_token = kTestContextToken;
  context.completion_callback = authentication_complete_callback_.Get();
  context.user_consent_already_given = true;
  Vcn3dsChallengeOptionMetadata metadata;
  metadata.success_query_param_name = "token";
  metadata.failure_query_param_name = "failure";
  context.challenge_option.vcn_3ds_metadata = std::move(metadata);
  window_manager().InitVcn3dsAuthentication(std::move(context));
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Tests that an error dialog is shown if the URL to open returned from the
// server has a non-HTTP/HTTPS scheme.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       Vcn3ds_InvokeUi_BadUrlScheme_ErrorDialogShown) {
  PaymentsWindowManager::Vcn3dsContext context;
  context.card = test::GetVirtualCard();
  context.context_token = kTestContextToken;
  context.completion_callback = authentication_complete_callback_.Get();
  context.user_consent_already_given = true;
  Vcn3dsChallengeOptionMetadata metadata;
  metadata.url_to_open = GURL("data:text/html,Hello");
  metadata.success_query_param_name = "token";
  metadata.failure_query_param_name = "failure";
  context.challenge_option.vcn_3ds_metadata = std::move(metadata);
  window_manager().InitVcn3dsAuthentication(std::move(context));
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Tests that an error dialog is shown if there is no success query param name
// returned from the server.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_EmptySuccessQueryParamName_ErrorDialogShown) {
  PaymentsWindowManager::Vcn3dsContext context;
  context.card = test::GetVirtualCard();
  context.context_token = kTestContextToken;
  context.completion_callback = authentication_complete_callback_.Get();
  context.user_consent_already_given = true;
  Vcn3dsChallengeOptionMetadata metadata;
  metadata.url_to_open = GURL(kTestUrl);
  metadata.failure_query_param_name = "failure";
  context.challenge_option.vcn_3ds_metadata = std::move(metadata);
  window_manager().InitVcn3dsAuthentication(std::move(context));
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Tests that an error dialog is shown if there is no failure query param name
// returned from the server.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_EmptyFailureQueryParamName_ErrorDialogShown) {
  PaymentsWindowManager::Vcn3dsContext context;
  context.card = test::GetVirtualCard();
  context.context_token = kTestContextToken;
  context.completion_callback = authentication_complete_callback_.Get();
  context.user_consent_already_given = true;
  Vcn3dsChallengeOptionMetadata metadata;
  metadata.url_to_open = GURL(kTestUrl);
  metadata.success_query_param_name = "token";
  context.challenge_option.vcn_3ds_metadata = std::move(metadata);
  window_manager().InitVcn3dsAuthentication(std::move(context));
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Test that the VCN 3DS flow started and consent dialog skipped histogram
// buckets are logged to when the flow starts.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_FlowStartedHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowStarted, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowStarted, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kUserConsentDialogSkipped, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kUserConsentDialogSkipped, 1);
}

// Test that the VCN 3DS pop-up is shown correctly, and on close an
// UnmaskCardRequest is triggered with the proper fields set if the right query
// params are present.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Vcn3ds_QueryParamsPresent) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a token query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();
  EXPECT_TRUE(test_api(window_manager()).GetFlowState().has_value());

  // Check that the flow was successful and an UnmaskCardRequest was triggered
  // with the correct fields set, and the progress dialog was shown.
  auto* autofill_client = client();
  EXPECT_TRUE(autofill_client->GetPaymentsAutofillClient()
                  ->autofill_progress_dialog_shown());
  const std::optional<UnmaskRequestDetails>& unmask_request =
      static_cast<TestPaymentsNetworkInterface*>(
          autofill_client->GetPaymentsAutofillClient()
              ->GetPaymentsNetworkInterface())
          ->unmask_request();
  ASSERT_TRUE(unmask_request.has_value());
  EXPECT_EQ(unmask_request->card,
            test_api(window_manager()).GetVcn3dsContext()->card);
  EXPECT_EQ(unmask_request->redirect_completion_result.value(),
            "sometesttoken");
  EXPECT_EQ(unmask_request->last_committed_primary_main_frame_origin,
            client()->GetLastCommittedPrimaryMainFrameOrigin().GetURL());

  // Simulate a response for the UnmaskCardRequest and ensure the callback is
  // run with the correct information.
  UnmaskResponseDetails response_details;
  response_details.with_real_pan("1111222233334444");
  response_details.with_dcvv("123");
  response_details.expiration_month = "01";
  response_details.expiration_year = "2030";
  test_api(window_manager())
      .OnVcn3dsAuthenticationResponseReceived(
          PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
          response_details);

  EXPECT_EQ(unmask_request->context_token, kTestContextToken);
  EXPECT_FALSE(unmask_request->risk_data.empty());
  ASSERT_TRUE(unmask_request->selected_challenge_option.has_value());
  EXPECT_EQ(
      unmask_request->selected_challenge_option->vcn_3ds_metadata->url_to_open,
      kTestUrl);
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse> response =
      authentication_response();
  ASSERT_TRUE(response.has_value());
  ASSERT_TRUE(response->card.has_value());
  EXPECT_EQ(response->card->number(),
            base::UTF8ToUTF16(response_details.real_pan));
  EXPECT_EQ(response->card->cvc(), base::UTF8ToUTF16(response_details.dcvv));
  int expiration_month;
  int expiration_year;
  base::StringToInt(response_details.expiration_month, &expiration_month);
  base::StringToInt(response_details.expiration_year, &expiration_year);
  EXPECT_EQ(response->card->expiration_month(), expiration_month);
  EXPECT_EQ(response->card->expiration_year(), expiration_year);
  EXPECT_EQ(response->card->record_type(),
            CreditCard::RecordType::kVirtualCard);
  EXPECT_FALSE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());
}

// Tests that the VCN 3DS flow succeeded histogram bucket is logged to when a
// successful flow is completed for VCN 3DS.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_QueryParamsPresent_SuccessHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a token query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  // Simulate a response for the UnmaskCardRequest and ensure the callback is
  // run with the correct information.
  UnmaskResponseDetails response_details;
  response_details.with_real_pan("1111222233334444");
  response_details.with_dcvv("123");
  response_details.expiration_month = "01";
  response_details.expiration_year = "2030";
  test_api(window_manager())
      .OnVcn3dsAuthenticationResponseReceived(
          PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
          response_details);

  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowSucceeded, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowSucceeded, 1);
}

// Tests that the VCN 3DS flow succeeded latency histogram bucket is logged to
// when a successful flow is completed for VCN 3DS.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_QueryParamsPresent_SuccessLatencyHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there are shouldProceed and token query params.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectTotalCount(kVcn3dsSuccessLatencyHistogramName, 1);
  histogram_tester_.ExpectTotalCount(kVcn3dsFailureLatencyHistogramName, 0);
}

// Tests that the VCN 3DS flow failure latency histogram bucket is logged to
// when a failed flow is completed for VCN 3DS.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_QueryParamsPresent_FailureLatencyHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a shouldProceed query param that denotes
  // failure.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?failure=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectTotalCount(kVcn3dsSuccessLatencyHistogramName, 0);
  histogram_tester_.ExpectTotalCount(kVcn3dsFailureLatencyHistogramName, 1);
}

// Test that the VCN 3DS pop-up is shown correctly, and on close an
// UnmaskCardRequest is triggered with the proper fields set if the right query
// params are present. Then mock an UnmaskCardRequest failure, and check that
// the requester was notified of this failure.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Vcn3ds_UnmaskCardRequestFailure) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a token query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();
  EXPECT_TRUE(test_api(window_manager()).GetFlowState().has_value());

  // Check that the flow was successful and an UnmaskCardRequest was triggered
  // with the correct fields set, and the progress dialog was shown.
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_progress_dialog_shown());
  const std::optional<UnmaskRequestDetails>& unmask_request =
      static_cast<TestPaymentsNetworkInterface*>(
          client()->GetPaymentsAutofillClient()->GetPaymentsNetworkInterface())
          ->unmask_request();
  ASSERT_TRUE(unmask_request.has_value());
  EXPECT_EQ(unmask_request->card,
            test_api(window_manager()).GetVcn3dsContext()->card);
  EXPECT_EQ(unmask_request->redirect_completion_result.value(),
            "sometesttoken");
  EXPECT_EQ(unmask_request->last_committed_primary_main_frame_origin,
            client()->GetLastCommittedPrimaryMainFrameOrigin().GetURL());

  // Simulate a response for the UnmaskCardRequest and ensure the callback is
  // run with the correct information.
  test_api(window_manager())
      .OnVcn3dsAuthenticationResponseReceived(
          PaymentsAutofillClient::PaymentsRpcResult::kPermanentFailure,
          UnmaskResponseDetails());

  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse> response =
      authentication_response();
  ASSERT_TRUE(response.has_value());
  EXPECT_FALSE(response->card.has_value());
  EXPECT_EQ(
      response->result,
      PaymentsWindowManager::Vcn3dsAuthenticationResult::kAuthenticationFailed);
}

// Tests that the VCN 3DS flow failed during second server call histogram bucket
// is logged to when a flow fails in the second UnmaskCardRequest.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_UnmaskCardRequestFailure_FailureHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a token query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  // Simulate a response for the UnmaskCardRequest and ensure the callback is
  // run with the correct information.
  test_api(window_manager())
      .OnVcn3dsAuthenticationResponseReceived(
          PaymentsAutofillClient::PaymentsRpcResult::kPermanentFailure,
          UnmaskResponseDetails());

  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowFailedWhileRetrievingVCN, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowFailedWhileRetrievingVCN, 1);
}

// Test that the VCN 3DS pop-up is shown correctly, and on close an
// UnmaskCardRequest is not triggered if the query params indicate the
// authentication failed.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_QueryParams_AuthenticationFailed) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a failure query param that denotes
  // the authentication failed.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?failure=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();
  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());

  // Check that the flow was ended and no UnmaskCardRequest was triggered.
  const std::optional<UnmaskRequestDetails>& unmask_request =
      static_cast<TestPaymentsNetworkInterface*>(
          client()->GetPaymentsAutofillClient()->GetPaymentsNetworkInterface())
          ->unmask_request();
  ASSERT_FALSE(unmask_request.has_value());
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse> response =
      authentication_response();
  ASSERT_TRUE(response.has_value());
  EXPECT_FALSE(response->card.has_value());
  EXPECT_EQ(
      response->result,
      PaymentsWindowManager::Vcn3dsAuthenticationResult::kAuthenticationFailed);
  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Tests that the VCN 3DS authentication failed histogram bucket is logged to
// when the authentication inside of the pop-up failed for VCN 3DS.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_QueryParams_AuthenticationFailed_FailureHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a failure query param that denotes
  // the authentication failed.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?failure=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kAuthenticationInsidePopupFailed, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kAuthenticationInsidePopupFailed, 1);
}

// Test that the VCN 3DS pop-up is shown correctly, and on close an
// UnmaskCardRequest is not triggered if there are no query params present.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Vcn3ds_NoQueryParamsAndPopupClosed) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  ClosePopupAndWait();

  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());

  // Check that the flow was ended and no UnmaskCardRequest was triggered.
  const std::optional<UnmaskRequestDetails>& unmask_request =
      static_cast<TestPaymentsNetworkInterface*>(
          client()->GetPaymentsAutofillClient()->GetPaymentsNetworkInterface())
          ->unmask_request();
  ASSERT_FALSE(unmask_request.has_value());
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse> response =
      authentication_response();
  ASSERT_TRUE(response.has_value());
  EXPECT_FALSE(response->card.has_value());
  EXPECT_EQ(response->result,
            PaymentsWindowManager::Vcn3dsAuthenticationResult::
                kAuthenticationNotCompleted);
  EXPECT_FALSE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Tests that the VCN 3DS flow cancelled histogram bucket is logged to when the
// user closes the pop-up.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_NoQueryParamsAndPopupClosed_CancelledHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  ClosePopupAndWait();

  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowCancelledUserClosedPopup, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kFlowCancelledUserClosedPopup, 1);
}

// Test that the VCN 3DS pop-up is shown correctly, and on close an
// UnmaskCardRequest is not triggered if the query params are invalid.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Vcn3ds_InvalidQueryParams) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is an unrecognized query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(
          GURL("https://site.example/?unrecognizedQueryParam=true"),
          content::Referrer(), WindowOpenDisposition::CURRENT_TAB,
          ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
          /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  ClosePopupAndWait();

  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());

  // Check that the flow was ended and no UnmaskCardRequest was triggered.
  const std::optional<UnmaskRequestDetails>& unmask_request =
      static_cast<TestPaymentsNetworkInterface*>(
          client()->GetPaymentsAutofillClient()->GetPaymentsNetworkInterface())
          ->unmask_request();
  ASSERT_FALSE(unmask_request.has_value());
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse> response =
      authentication_response();
  ASSERT_TRUE(response.has_value());
  EXPECT_FALSE(response->card.has_value());
  EXPECT_EQ(response->result,
            PaymentsWindowManager::Vcn3dsAuthenticationResult::
                kAuthenticationNotCompleted);
  EXPECT_FALSE(
      client()->GetPaymentsAutofillClient()->autofill_error_dialog_shown());
}

// Test that the VCN 3DS pop-up is shown correctly, and when the user cancels
// the progress dialog, the state of the PaymentsWindowManager in relation to
// the ongoing UnmaskCardRequest is reset.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Vcn3ds_ProgressDialogCancelled) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a token query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();
  EXPECT_TRUE(test_api(window_manager()).GetFlowState().has_value());

  EXPECT_TRUE(
      client()->GetPaymentsAutofillClient()->autofill_progress_dialog_shown());

  // Check that the state of the PaymentsWindowManager is reset correctly
  // if the user cancels the progress dialog.
  EXPECT_TRUE(test_api(window_manager()).GetVcn3dsContext().has_value());
  test_api(window_manager()).OnVcn3dsAuthenticationProgressDialogCancelled();
  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse> response =
      authentication_response();
  ASSERT_TRUE(response.has_value());
  EXPECT_FALSE(response->card.has_value());
  EXPECT_EQ(response->result,
            PaymentsWindowManager::Vcn3dsAuthenticationResult::
                kAuthenticationNotCompleted);
}

// Tests that the VCN 3DS progress dialog cancelled histogram bucket is logged
// to when the progress dialog is cancelled during the VCN 3DS flow.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Vcn3ds_ProgressDialogCancelled_ProgressDialogCancelledHistogramBucketLogs) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Navigate to a page where there is a token query param.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL("https://site.example/?token=sometesttoken"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  test_api(window_manager()).OnVcn3dsAuthenticationProgressDialogCancelled();

  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kProgressDialogCancelled, 1);
  histogram_tester_.ExpectBucketCount(
      kVcn3dsFlowEventsConsentAlreadyGivenHistogramName,
      autofill_metrics::Vcn3dsFlowEvent::kProgressDialogCancelled, 1);
}

#if BUILDFLAG(IS_LINUX)
// Tests that if a VCN 3DS flow is ongoing, and the original tab is set active,
// the payments window manager popup's web contents are re-activated.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Vcn3ds_OriginalTabSetLastActive) {
  ShowUi("Vcn3ds_ConsentAlreadyGiven");
  EXPECT_TRUE(VerifyUi());

  // Activate the original browser and check that the browser containing the
  // pop-up's web contents becomes the last active browser.
  ui_test_utils::BrowserActivationWaiter waiter(popup_browser());
  browser()->GetWindow()->Activate();
  waiter.WaitForActivation();
  EXPECT_TRUE(GetLastActiveBrowserWindowInterfaceWithAnyProfile()
                  ->GetTabStripModel()
                  ->GetActiveWebContents() == GetPopupWebContents());
}
#endif  // #if BUILDFLAG(IS_LINUX)

// Test that the BNPL pop-up is shown correctly, and on close the completion
// callback is triggered with a success result if the flow was successful.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_Success) {
  ShowUi("Bnpl_Affirm");
  EXPECT_TRUE(VerifyUi());

  GURL success_url =
      GURL(std::string(kBnplSuccessUrlPrefix) + "testqueryparam?param1=true");
  EXPECT_CALL(
      bnpl_popup_closed_callback_,
      Run(PaymentsWindowManager::BnplFlowResult::kSuccess, success_url));

  // Navigate to the URL that denotes success inside of the BNPL pop-up.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(success_url, content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());
}

// Test that the PopupWindowShown histogram is logged if the BNPL pop-up is
// shown.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_PopupWindowShownLogged) {
  ShowUi("Bnpl_Affirm");

  histogram_tester_.ExpectUniqueSample(
      /*name=*/"Autofill.Bnpl.PopupWindowShown.Affirm",
      /*sample=*/true, /*expected_bucket_count=*/1);
}

// Test that the BNPL PopupWindowResult histogram logs a success result if the
// pop-up flow was successful.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_Success_PopupWindowResultLogged) {
  ShowUi("Bnpl_Affirm");

  // Navigate to the URL that denotes success inside of the BNPL pop-up.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL(std::string(kBnplSuccessUrlPrefix) +
                                  "testqueryparam?param1=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectUniqueSample(
      /*name=*/"Autofill.Bnpl.PopupWindowResult.Affirm",
      /*sample=*/PaymentsWindowManager::BnplFlowResult::kSuccess,
      /*expected_bucket_count=*/1);
}

// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Bnpl_Success_PopupWindowLatencyLogged) {
  ShowUi("Bnpl_Affirm");

  // Navigate to the URL that denotes success inside of the BNPL pop-up.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL(std::string(kBnplSuccessUrlPrefix) +
                                  "testqueryparam?param1=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectTotalCount(
      "Autofill.Bnpl.PopupWindowLatency.Affirm.Success", 1);
}

// Test that the BNPL pop-up is shown correctly, and on close the completion
// callback is triggered with a failure result if the flow was a failure.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_Failure) {
  ShowUi("Bnpl_Affirm");
  EXPECT_TRUE(VerifyUi());

  GURL failure_url =
      GURL(std::string(kBnplFailureUrlPrefix) + "testqueryparam?param1=true");
  EXPECT_CALL(
      bnpl_popup_closed_callback_,
      Run(PaymentsWindowManager::BnplFlowResult::kFailure, failure_url));

  // Navigate to the URL that denotes failure inside of the BNPL pop-up.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(failure_url, content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());
}

// Test that the BNPL PopupWindowResult histogram logs a failure result if the
// pop-up flow was a failure.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_Failure_PopupWindowResultLogged) {
  ShowUi("Bnpl_Affirm");

  // Navigate to the URL that denotes failure inside of the BNPL pop-up.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL(std::string(kBnplFailureUrlPrefix) +
                                  "testqueryparam?param1=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectUniqueSample(
      /*name=*/"Autofill.Bnpl.PopupWindowResult.Affirm",
      /*sample=*/PaymentsWindowManager::BnplFlowResult::kFailure,
      /*expected_bucket_count=*/1);
}

// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Bnpl_Failure_PopupWindowLatencyLogged) {
  ShowUi("Bnpl_Affirm");

  // Navigate to the URL that denotes success inside of the BNPL pop-up.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(GURL(std::string(kBnplFailureUrlPrefix) +
                                  "testqueryparam?param1=true"),
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  WaitForPopupClose();

  histogram_tester_.ExpectTotalCount(
      "Autofill.Bnpl.PopupWindowLatency.Affirm.Failure", 1);
}

// Test that the BNPL pop-up is shown correctly, and on close the completion
// callback is triggered with a "user closed" result if the flow was closed by
// the user.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_UserClosedPopup) {
  ShowUi("Bnpl_Affirm");
  EXPECT_TRUE(VerifyUi());

  EXPECT_CALL(bnpl_popup_closed_callback_,
              Run(PaymentsWindowManager::BnplFlowResult::kUserClosed,
                  GURL(kBnplInitialUrl)));

  ClosePopupAndWait();

  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());
}

// Test that the PopupWindowResult histogram logs a "user closed" result if the
// pop-up flow was closed by the user.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Bnpl_UserClosedPopup_PopupWindowResultLogged) {
  ShowUi("Bnpl_Affirm");
  ClosePopupAndWait();

  histogram_tester_.ExpectUniqueSample(
      /*name=*/"Autofill.Bnpl.PopupWindowResult.Affirm",
      /*sample=*/PaymentsWindowManager::BnplFlowResult::kUserClosed,
      /*expected_bucket_count=*/1);
}

// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(
    DesktopPaymentsWindowManagerInteractiveUiTest,
    DISABLED_InvokeUi_Bnpl_UserClosedPopup_PopupWindowLatencyLogged) {
  ShowUi("Bnpl_Affirm");
  ClosePopupAndWait();

  histogram_tester_.ExpectTotalCount(
      "Autofill.Bnpl.PopupWindowLatency.Affirm.UserClosed", 1);
}

// Test that the BNPL pop-up is shown correctly, and on close the completion
// callback is triggered with a "user closed" result if the flow was closed and
// the URL contained the success URL prefix, but the success URL prefix was not
// its prefix.
// TODO(crbug.com/435092593): Re-enable once flakiness is fixed.
IN_PROC_BROWSER_TEST_F(DesktopPaymentsWindowManagerInteractiveUiTest,
                       DISABLED_InvokeUi_Bnpl_UrlIsNotAPrefix) {
  ShowUi("Bnpl_Affirm");
  EXPECT_TRUE(VerifyUi());

  GURL success_url_with_different_prefix =
      GURL("somestring" + std::string(kBnplSuccessUrlPrefix));
  EXPECT_CALL(bnpl_popup_closed_callback_,
              Run(PaymentsWindowManager::BnplFlowResult::kUserClosed,
                  success_url_with_different_prefix));

  // Navigate to the URL that denotes the BNPL pop-up has not completed yet.
  GetPopupWebContents()->OpenURL(
      content::OpenURLParams(success_url_with_different_prefix,
                             content::Referrer(),
                             WindowOpenDisposition::CURRENT_TAB,
                             ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
                             /*is_renderer_initiated=*/false),
      /*navigation_handle_callback=*/{});

  ClosePopupAndWait();

  EXPECT_FALSE(test_api(window_manager()).GetFlowState().has_value());
}

// Integration test using Kombucha to ensure that the consent dialog creates a
// new pop-up when the ok button is clicked, and cancels the flow when the
// cancel button is clicked.
class PaymentsWindowUserConsentDialogIntegrationTest
    : public InteractiveBrowserTest {
 public:
  PaymentsWindowUserConsentDialogIntegrationTest() = default;
  PaymentsWindowUserConsentDialogIntegrationTest(
      const PaymentsWindowUserConsentDialogIntegrationTest&) = delete;
  PaymentsWindowUserConsentDialogIntegrationTest& operator=(
      const PaymentsWindowUserConsentDialogIntegrationTest&) = delete;
  ~PaymentsWindowUserConsentDialogIntegrationTest() override = default;

 protected:
  InteractiveBrowserTestApi::MultiStep TriggerDialogAndWaitForShow(
      ElementSpecifier element_specifier) {
    return Steps(TriggerDialog(),
                 // TODO(crbug.com/332603033): Tab-modal dialogs on MacOS run in
                 // a different context.
                 InAnyContext(WaitForShow(element_specifier)));
  }

  DesktopPaymentsWindowManager& GetWindowManager() {
    // The original page is always created first.
    auto* original_page_web_contents =
        browser()->GetTabStripModel()->GetActiveWebContents();
    return *static_cast<DesktopPaymentsWindowManager*>(
        test_autofill_client_injector_[original_page_web_contents]
            ->GetPaymentsAutofillClient()
            ->GetPaymentsWindowManager());
  }

  void set_authentication_response(
      PaymentsWindowManager::Vcn3dsAuthenticationResponse
          authentication_response) {
    authentication_response_ = std::move(authentication_response);
  }
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse>
  authentication_response() {
    return authentication_response_;
  }

  base::HistogramTester histogram_tester_;

 private:
  InteractiveTestApi::StepBuilder TriggerDialog() {
    return Do([this]() {
      PaymentsWindowManager::Vcn3dsContext context;
      context.card = test::GetVirtualCard();
      context.context_token = kTestContextToken;
      Vcn3dsChallengeOptionMetadata metadata;
      metadata.url_to_open = GURL(kTestUrl);
      metadata.success_query_param_name = "token";
      metadata.failure_query_param_name = "failure";
      context.challenge_option.vcn_3ds_metadata = std::move(metadata);
      context.completion_callback = authentication_complete_callback_.Get();
      context.user_consent_already_given = false;
      ON_CALL(authentication_complete_callback_, Run)
          .WillByDefault(
              [this](PaymentsWindowManager::Vcn3dsAuthenticationResponse
                         authentication_response) {
                set_authentication_response(std::move(authentication_response));
              });
      GetWindowManager().InitVcn3dsAuthentication(std::move(context));
    });
  }

  TestAutofillClientInjector<TestContentAutofillClientForWindowManagerTest>
      test_autofill_client_injector_;

  base::MockCallback<
      PaymentsWindowManager::OnVcn3dsAuthenticationCompleteCallback>
      authentication_complete_callback_;
  std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse>
      authentication_response_;
};

// Ensures that the flow started, consent not given yet histogram bucket is
// logged to when a payments window flow is started without consent already
// given.
IN_PROC_BROWSER_TEST_F(PaymentsWindowUserConsentDialogIntegrationTest,
                       FlowStartedConsentNotGivenYetHistogramBucketLogs) {
  RunTestSequence(
      TriggerDialogAndWaitForShow(views::DialogClientView::kOkButtonElementId),
      Check([this]() {
        return histogram_tester_.GetBucketCount(
                   kVcn3dsFlowEventsConsentNotGivenYetHistogramName,
                   autofill_metrics::Vcn3dsFlowEvent::kFlowStarted) == 1;
      }));
}

// Ensures the UI can be shown, and verifies that accepting the dialog runs the
// accept callback and creates the pop-up.
IN_PROC_BROWSER_TEST_F(PaymentsWindowUserConsentDialogIntegrationTest,
                       DialogAccepted) {
  EXPECT_EQ(GlobalBrowserCollection::GetInstance()->GetSize(), 1U);

  RunTestSequence(
      TriggerDialogAndWaitForShow(views::DialogClientView::kOkButtonElementId),
      // TriggerDialogAndWaitForShow() changes the context, so the same context
      // must be used.
      InSameContext(
          PressButton(views::DialogClientView::kOkButtonElementId),
          AfterHide(PaymentsWindowUserConsentDialogView::kTopViewId, []() {
            EXPECT_EQ(GlobalBrowserCollection::GetInstance()->GetSize(), 2U);
          })));
}

// Tests that the VCN 3DS consent dialog accepted histogram bucket is logged to
// when the consent dialog is accepted.
IN_PROC_BROWSER_TEST_F(PaymentsWindowUserConsentDialogIntegrationTest,
                       DialogAccepted_AcceptedHistogramBucketLogs) {
  EXPECT_EQ(GlobalBrowserCollection::GetInstance()->GetSize(), 1U);

  RunTestSequence(
      TriggerDialogAndWaitForShow(views::DialogClientView::kOkButtonElementId),
      // TriggerDialogAndWaitForShow() changes the context, so the same context
      // must be used.
      InSameContext(
          PressButton(views::DialogClientView::kOkButtonElementId),
          AfterHide(PaymentsWindowUserConsentDialogView::kTopViewId,
                    []() {
                      EXPECT_EQ(
                          GlobalBrowserCollection::GetInstance()->GetSize(),
                          2U);
                    }),
          Check([this]() {
            return histogram_tester_.GetBucketCount(
                       kVcn3dsFlowEventsHistogramName,
                       autofill_metrics::Vcn3dsFlowEvent::
                           kUserConsentDialogAccepted) == 1 &&
                   histogram_tester_.GetBucketCount(
                       kVcn3dsFlowEventsConsentNotGivenYetHistogramName,
                       autofill_metrics::Vcn3dsFlowEvent::
                           kUserConsentDialogAccepted) == 1;
          })));
}

// Ensures the UI can be shown, and verifies that cancelling the dialog runs the
// cancel callback and resets the state.
IN_PROC_BROWSER_TEST_F(PaymentsWindowUserConsentDialogIntegrationTest,
                       DialogCancelled) {
  RunTestSequence(
      TriggerDialogAndWaitForShow(
          views::DialogClientView::kCancelButtonElementId),
      // TriggerDialogAndWaitForShow() changes the context, so the same context
      // must be used.
      InSameContext(
          PressButton(views::DialogClientView::kCancelButtonElementId),
          AfterHide(PaymentsWindowUserConsentDialogView::kTopViewId, [this]() {
            EXPECT_FALSE(
                test_api(GetWindowManager()).GetFlowState().has_value());
            std::optional<PaymentsWindowManager::Vcn3dsAuthenticationResponse>
                response = authentication_response();
            ASSERT_TRUE(response.has_value());
            EXPECT_FALSE(response->card.has_value());
          })));
}

// Tests that the VCN 3DS consent dialog declined histogram bucket is logged to
// when the consent dialog is declined.
IN_PROC_BROWSER_TEST_F(PaymentsWindowUserConsentDialogIntegrationTest,
                       DialogDeclined_DeclinedHistogramBucketLogs) {
  RunTestSequence(
      TriggerDialogAndWaitForShow(
          views::DialogClientView::kCancelButtonElementId),
      // TriggerDialogAndWaitForShow() changes the context, so the same context
      // must be used.
      InSameContext(
          PressButton(views::DialogClientView::kCancelButtonElementId),
          Check([this]() {
            return histogram_tester_.GetBucketCount(
                       kVcn3dsFlowEventsHistogramName,
                       autofill_metrics::Vcn3dsFlowEvent::
                           kUserConsentDialogDeclined) == 1 &&
                   histogram_tester_.GetBucketCount(
                       kVcn3dsFlowEventsConsentNotGivenYetHistogramName,
                       autofill_metrics::Vcn3dsFlowEvent::
                           kUserConsentDialogDeclined) == 1;
          })));
}

}  // namespace
}  // namespace autofill::payments
